@dodo-planet/cli 0.1.4 → 0.1.6
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/dist/index.js +692 -127
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23,20 +23,20 @@ function getConfigDir() {
|
|
|
23
23
|
function getConfigPath() {
|
|
24
24
|
return join(getConfigDir(), "config.json");
|
|
25
25
|
}
|
|
26
|
-
async function ensureDir(
|
|
27
|
-
if (!existsSync(
|
|
28
|
-
await mkdir(
|
|
26
|
+
async function ensureDir(path3) {
|
|
27
|
+
if (!existsSync(path3)) {
|
|
28
|
+
await mkdir(path3, { recursive: true, mode: 448 });
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
async function readConfig() {
|
|
32
32
|
const envApiUrl = process.env.DODO_API_URL?.trim();
|
|
33
33
|
const envLocale = process.env.DODO_LOCALE?.trim();
|
|
34
34
|
const envOutput = process.env.DODO_OUTPUT?.trim();
|
|
35
|
-
const
|
|
35
|
+
const path3 = getConfigPath();
|
|
36
36
|
let fileCfg = {};
|
|
37
|
-
if (existsSync(
|
|
37
|
+
if (existsSync(path3)) {
|
|
38
38
|
try {
|
|
39
|
-
fileCfg = JSON.parse(await readFile(
|
|
39
|
+
fileCfg = JSON.parse(await readFile(path3, "utf8"));
|
|
40
40
|
} catch {
|
|
41
41
|
}
|
|
42
42
|
}
|
|
@@ -89,10 +89,10 @@ function getCredentialsPath() {
|
|
|
89
89
|
async function getToken() {
|
|
90
90
|
const fromEnv = process.env.DODO_TOKEN;
|
|
91
91
|
if (fromEnv && fromEnv.trim()) return fromEnv.trim();
|
|
92
|
-
const
|
|
93
|
-
if (!existsSync2(
|
|
92
|
+
const path3 = getCredentialsPath();
|
|
93
|
+
if (!existsSync2(path3)) return null;
|
|
94
94
|
try {
|
|
95
|
-
const stat = statSync(
|
|
95
|
+
const stat = statSync(path3);
|
|
96
96
|
const mode = stat.mode & 511;
|
|
97
97
|
if (mode !== 384 && process.env.DODO_STRICT_PERMS === "1") {
|
|
98
98
|
throw new Error(
|
|
@@ -102,7 +102,7 @@ async function getToken() {
|
|
|
102
102
|
} catch {
|
|
103
103
|
}
|
|
104
104
|
try {
|
|
105
|
-
const raw = await readFile2(
|
|
105
|
+
const raw = await readFile2(path3, "utf8");
|
|
106
106
|
const parsed = JSON.parse(raw);
|
|
107
107
|
return parsed.token || null;
|
|
108
108
|
} catch {
|
|
@@ -119,14 +119,14 @@ async function saveToken(token, travelerId) {
|
|
|
119
119
|
travelerId,
|
|
120
120
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
121
121
|
};
|
|
122
|
-
const
|
|
123
|
-
await writeFile2(
|
|
124
|
-
await chmod(
|
|
122
|
+
const path3 = getCredentialsPath();
|
|
123
|
+
await writeFile2(path3, JSON.stringify(payload, null, 2), { mode: 384 });
|
|
124
|
+
await chmod(path3, 384);
|
|
125
125
|
}
|
|
126
126
|
async function clearToken() {
|
|
127
|
-
const
|
|
128
|
-
if (existsSync2(
|
|
129
|
-
await unlink(
|
|
127
|
+
const path3 = getCredentialsPath();
|
|
128
|
+
if (existsSync2(path3)) {
|
|
129
|
+
await unlink(path3);
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
132
|
function isTokenFromEnv() {
|
|
@@ -165,8 +165,8 @@ var init_exit_codes = __esm({
|
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
// src/lib/api-client.ts
|
|
168
|
-
function buildUrl(base,
|
|
169
|
-
const url = new URL(
|
|
168
|
+
function buildUrl(base, path3, query) {
|
|
169
|
+
const url = new URL(path3, base);
|
|
170
170
|
if (query) {
|
|
171
171
|
for (const [k, v] of Object.entries(query)) {
|
|
172
172
|
if (v !== void 0 && v !== "") url.searchParams.set(k, v);
|
|
@@ -174,9 +174,9 @@ function buildUrl(base, path2, query) {
|
|
|
174
174
|
}
|
|
175
175
|
return url.toString();
|
|
176
176
|
}
|
|
177
|
-
async function apiRequest(
|
|
177
|
+
async function apiRequest(path3, opts = {}) {
|
|
178
178
|
const cfg = await readConfig();
|
|
179
|
-
const url = buildUrl(cfg.apiUrl,
|
|
179
|
+
const url = buildUrl(cfg.apiUrl, path3, opts.query);
|
|
180
180
|
const headers = {
|
|
181
181
|
accept: "application/json",
|
|
182
182
|
...opts.headers
|
|
@@ -381,10 +381,10 @@ function getStatePath() {
|
|
|
381
381
|
return join3(getConfigDir(), "state.json");
|
|
382
382
|
}
|
|
383
383
|
async function readState() {
|
|
384
|
-
const
|
|
385
|
-
if (!existsSync3(
|
|
384
|
+
const path3 = getStatePath();
|
|
385
|
+
if (!existsSync3(path3)) return {};
|
|
386
386
|
try {
|
|
387
|
-
const raw = await readFile3(
|
|
387
|
+
const raw = await readFile3(path3, "utf8");
|
|
388
388
|
return JSON.parse(raw);
|
|
389
389
|
} catch {
|
|
390
390
|
return {};
|
|
@@ -473,7 +473,12 @@ var init_function_catalog_shared = __esm({
|
|
|
473
473
|
{ name: "get_friends", category: "friend", verb: "list", requiresTrip: false, isWrite: false, isDestructive: false },
|
|
474
474
|
{ name: "add_friend", category: "friend", verb: "add", requiresTrip: false, isWrite: true, isDestructive: false },
|
|
475
475
|
{ name: "get_invitations", category: "invite", verb: "list", requiresTrip: true, isWrite: false, isDestructive: false },
|
|
476
|
-
{ name: "invite_to_trip", category: "invite", verb: "create", requiresTrip: true, isWrite: true, isDestructive: false }
|
|
476
|
+
{ name: "invite_to_trip", category: "invite", verb: "create", requiresTrip: true, isWrite: true, isDestructive: false },
|
|
477
|
+
// ── 여행 프로필 (4개, M2)
|
|
478
|
+
{ name: "get_travel_profile", category: "profile", verb: "show", requiresTrip: false, isWrite: false, isDestructive: false },
|
|
479
|
+
{ name: "update_travel_profile_section", category: "profile", verb: "update", requiresTrip: false, isWrite: true, isDestructive: false },
|
|
480
|
+
{ name: "finalize_travel_profile", category: "profile", verb: "finalize", requiresTrip: false, isWrite: false, isDestructive: false, isBuilderOnly: true },
|
|
481
|
+
{ name: "clear_travel_profile", category: "profile", verb: "clear", requiresTrip: false, isWrite: true, isDestructive: true }
|
|
477
482
|
];
|
|
478
483
|
CATALOG_BY_NAME = new Map(
|
|
479
484
|
FUNCTION_CATALOG.map((meta) => [meta.name, meta])
|
|
@@ -501,6 +506,14 @@ async function runFunctionCommand(opts) {
|
|
|
501
506
|
if (ctx.mode === "json") emitJsonError("catalog_missing", msg);
|
|
502
507
|
else printError(msg, ctx);
|
|
503
508
|
process.exit(ExitCode.GeneralError);
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (meta.isBuilderOnly) {
|
|
512
|
+
const msg = `${opts.function}\uC740(\uB294) \uBE4C\uB354 \uC804\uC6A9 \uD568\uC218\uC785\uB2C8\uB2E4. \`dodo profile chat\` \uC73C\uB85C \uC9C4\uD589\uD558\uC138\uC694.`;
|
|
513
|
+
if (ctx.mode === "json") emitJsonError("builder_only", msg);
|
|
514
|
+
else printError(msg, ctx);
|
|
515
|
+
process.exit(ExitCode.InvalidArgs);
|
|
516
|
+
return;
|
|
504
517
|
}
|
|
505
518
|
let tripId;
|
|
506
519
|
if (!opts.noTripContext) {
|
|
@@ -576,7 +589,7 @@ var init_command_helpers = __esm({
|
|
|
576
589
|
});
|
|
577
590
|
|
|
578
591
|
// src/index.ts
|
|
579
|
-
import { defineCommand as
|
|
592
|
+
import { defineCommand as defineCommand17, runMain } from "citty";
|
|
580
593
|
|
|
581
594
|
// src/commands/auth.ts
|
|
582
595
|
init_credentials();
|
|
@@ -1006,7 +1019,8 @@ var create = defineCommand3({
|
|
|
1006
1019
|
name: args.name,
|
|
1007
1020
|
start_date: args["start-date"],
|
|
1008
1021
|
end_date: args["end-date"],
|
|
1009
|
-
|
|
1022
|
+
// 서버 router는 args.country_code를 읽음 (declarations.ts의 create_trip)
|
|
1023
|
+
country_code: args.country,
|
|
1010
1024
|
cities: cities ? JSON.stringify(cities) : void 0,
|
|
1011
1025
|
...extraArgs
|
|
1012
1026
|
},
|
|
@@ -1029,13 +1043,539 @@ var tripCommand = defineCommand3({
|
|
|
1029
1043
|
subCommands: { list, current, switch: switchCmd, create }
|
|
1030
1044
|
});
|
|
1031
1045
|
|
|
1046
|
+
// src/commands/profile.ts
|
|
1047
|
+
init_api_client();
|
|
1048
|
+
init_output();
|
|
1049
|
+
init_config();
|
|
1050
|
+
init_credentials();
|
|
1051
|
+
init_exit_codes();
|
|
1052
|
+
init_prompt();
|
|
1053
|
+
import { defineCommand as defineCommand4 } from "citty";
|
|
1054
|
+
import { mkdtemp, writeFile as writeFile4, readFile as readFile4, rm } from "fs/promises";
|
|
1055
|
+
import { tmpdir } from "os";
|
|
1056
|
+
import path2 from "path";
|
|
1057
|
+
import { spawn } from "child_process";
|
|
1058
|
+
function splitProfileBody(text3) {
|
|
1059
|
+
const re = /^[ \t]*-{3,}[ \t]*safety[ \t]*-{3,}[ \t]*$/im;
|
|
1060
|
+
const match = re.exec(text3);
|
|
1061
|
+
if (!match) return { summary: text3.trim(), safety_notes: "" };
|
|
1062
|
+
return {
|
|
1063
|
+
summary: text3.slice(0, match.index).trim(),
|
|
1064
|
+
safety_notes: text3.slice(match.index + match[0].length).trim()
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
async function runEditorImpl(filepath) {
|
|
1068
|
+
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
1069
|
+
await new Promise((resolve, reject) => {
|
|
1070
|
+
const child = spawn(editor, [filepath], { stdio: "inherit" });
|
|
1071
|
+
child.on(
|
|
1072
|
+
"exit",
|
|
1073
|
+
(code) => code === 0 ? resolve() : reject(new Error(`${editor} exited with code ${code}`))
|
|
1074
|
+
);
|
|
1075
|
+
child.on("error", reject);
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
var _internal = {
|
|
1079
|
+
runEditor: runEditorImpl,
|
|
1080
|
+
/** 편집된 임시 파일을 다시 읽는다. utf8 디코딩까지 책임진다. */
|
|
1081
|
+
readEditedFile: async (filepath) => (await readFile4(filepath, "utf8")).toString(),
|
|
1082
|
+
/**
|
|
1083
|
+
* 임시 파일에 초기 본문을 쓴다.
|
|
1084
|
+
*
|
|
1085
|
+
* 테스트가 실패 시나리오(ENOSPC/EACCES)를 주입하기 위해 `_internal`을 거쳐 호출한다.
|
|
1086
|
+
* ESM에서는 `node:fs/promises`의 named export를 `vi.spyOn`으로 갈아끼울 수 없어
|
|
1087
|
+
* (module namespace not configurable) `_internal` namespace를 거치는 것이 유일한 안전 경로.
|
|
1088
|
+
*/
|
|
1089
|
+
writeFile: async (filepath, contents) => {
|
|
1090
|
+
await writeFile4(filepath, contents, "utf8");
|
|
1091
|
+
},
|
|
1092
|
+
/** 임시 디렉토리를 통째로 제거. ESM spy 한계 때문에 `_internal`을 거친다. */
|
|
1093
|
+
rm: async (target) => {
|
|
1094
|
+
await rm(target, { recursive: true, force: true });
|
|
1095
|
+
}
|
|
1096
|
+
};
|
|
1097
|
+
var show = defineCommand4({
|
|
1098
|
+
meta: { name: "show", description: "\uD65C\uC131 \uC5EC\uD589 \uD504\uB85C\uD544 + \uD1A0\uAE00 + \uC548\uC804 \uB178\uD2B8 \uCD9C\uB825." },
|
|
1099
|
+
args: {
|
|
1100
|
+
locale: { type: "string", description: "ko | en | es | fr" },
|
|
1101
|
+
output: { type: "string", description: "pretty | json" }
|
|
1102
|
+
},
|
|
1103
|
+
async run({ args }) {
|
|
1104
|
+
const ctx = await resolveOutputContext(args.output);
|
|
1105
|
+
const locale = await resolveLocale(args.locale);
|
|
1106
|
+
try {
|
|
1107
|
+
const result = await executeFunction(
|
|
1108
|
+
"get_travel_profile",
|
|
1109
|
+
{},
|
|
1110
|
+
{ locale }
|
|
1111
|
+
);
|
|
1112
|
+
if (ctx.mode === "json") {
|
|
1113
|
+
emitJsonOk({ profile: result.profile, enabled: result.enabled });
|
|
1114
|
+
return;
|
|
1115
|
+
}
|
|
1116
|
+
const c = colorize(ctx);
|
|
1117
|
+
if (!result.profile) {
|
|
1118
|
+
printLine(
|
|
1119
|
+
c.dim("\uC5EC\uD589 \uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `dodo profile chat` \uC73C\uB85C \uBE4C\uB354\uB97C \uC2DC\uC791\uD558\uC138\uC694.")
|
|
1120
|
+
);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const toggleLabel = result.enabled ? c.green("(ON)") : c.dim("(OFF)");
|
|
1124
|
+
printLine(c.bold(`\uC5EC\uD589 \uD504\uB85C\uD544 ${toggleLabel}`));
|
|
1125
|
+
printLine("");
|
|
1126
|
+
printLine(c.bold("\uC694\uC57D:"));
|
|
1127
|
+
printLine(result.profile.summary);
|
|
1128
|
+
if (result.profile.safety_notes && result.profile.safety_notes.trim()) {
|
|
1129
|
+
printLine("");
|
|
1130
|
+
printLine(c.bold("\uC548\uC804 \uB178\uD2B8:"));
|
|
1131
|
+
printLine(result.profile.safety_notes);
|
|
1132
|
+
}
|
|
1133
|
+
printLine("");
|
|
1134
|
+
printLine(c.dim(`\uB9C8\uC9C0\uB9C9 \uC5C5\uB370\uC774\uD2B8: ${result.profile.updated_at}`));
|
|
1135
|
+
} catch (err) {
|
|
1136
|
+
if (err instanceof ApiError) {
|
|
1137
|
+
if (ctx.mode === "json") emitJsonError("show_failed", err.message);
|
|
1138
|
+
else printError(err.message, ctx);
|
|
1139
|
+
process.exit(err.exitCode);
|
|
1140
|
+
}
|
|
1141
|
+
throw err;
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
var toggle = defineCommand4({
|
|
1146
|
+
meta: { name: "toggle", description: "\uC5EC\uD589 \uD504\uB85C\uD544 \uD65C\uC131/\uBE44\uD65C\uC131 \uC804\uD658." },
|
|
1147
|
+
args: {
|
|
1148
|
+
state: {
|
|
1149
|
+
type: "positional",
|
|
1150
|
+
description: "on | off",
|
|
1151
|
+
// citty가 누락 시 자동 에러를 내지 않도록 false. 우리가 직접 검증한다.
|
|
1152
|
+
required: false
|
|
1153
|
+
},
|
|
1154
|
+
output: { type: "string", description: "pretty | json" }
|
|
1155
|
+
},
|
|
1156
|
+
async run({ args }) {
|
|
1157
|
+
const ctx = await resolveOutputContext(args.output);
|
|
1158
|
+
if (args.state !== "on" && args.state !== "off") {
|
|
1159
|
+
const msg = "Usage: dodo profile toggle <on|off>";
|
|
1160
|
+
if (ctx.mode === "json") emitJsonError("invalid_args", msg);
|
|
1161
|
+
else printError(msg, ctx);
|
|
1162
|
+
process.exit(ExitCode.InvalidArgs);
|
|
1163
|
+
return;
|
|
1164
|
+
}
|
|
1165
|
+
const enabled = args.state === "on";
|
|
1166
|
+
try {
|
|
1167
|
+
const result = await apiRequest(
|
|
1168
|
+
"/api/travelers/me/active-profile",
|
|
1169
|
+
{ method: "POST", body: { enabled } }
|
|
1170
|
+
);
|
|
1171
|
+
if (ctx.mode === "json") emitJsonOk(result);
|
|
1172
|
+
else
|
|
1173
|
+
printLine(
|
|
1174
|
+
colorize(ctx).green(`\u2713 \uD504\uB85C\uD544 ${enabled ? "\uD65C\uC131\uD654" : "\uBE44\uD65C\uC131\uD654"}\uB428`)
|
|
1175
|
+
);
|
|
1176
|
+
} catch (err) {
|
|
1177
|
+
if (err instanceof ApiError) {
|
|
1178
|
+
if (ctx.mode === "json") emitJsonError("toggle_failed", err.message);
|
|
1179
|
+
else printError(err.message, ctx);
|
|
1180
|
+
process.exit(err.exitCode);
|
|
1181
|
+
}
|
|
1182
|
+
throw err;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
var edit = defineCommand4({
|
|
1187
|
+
meta: { name: "edit", description: "$EDITOR\uB85C \uD504\uB85C\uD544\uC744 \uC9C1\uC811 \uD3B8\uC9D1 (\uB099\uAD00\uC801 \uB3D9\uC2DC\uC131)." },
|
|
1188
|
+
args: {
|
|
1189
|
+
locale: { type: "string", description: "ko | en | es | fr" },
|
|
1190
|
+
output: { type: "string", description: "pretty | json" }
|
|
1191
|
+
},
|
|
1192
|
+
async run({ args }) {
|
|
1193
|
+
const ctx = await resolveOutputContext(args.output);
|
|
1194
|
+
const locale = await resolveLocale(args.locale);
|
|
1195
|
+
try {
|
|
1196
|
+
const current2 = await executeFunction(
|
|
1197
|
+
"get_travel_profile",
|
|
1198
|
+
{},
|
|
1199
|
+
{ locale }
|
|
1200
|
+
);
|
|
1201
|
+
if (!current2.profile) {
|
|
1202
|
+
const msg = "\uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. `dodo profile chat`\uC73C\uB85C \uBE4C\uB354\uB97C \uC2DC\uC791\uD558\uC138\uC694.";
|
|
1203
|
+
if (ctx.mode === "json") emitJsonError("no_profile", msg);
|
|
1204
|
+
else printError(msg, ctx);
|
|
1205
|
+
process.exit(ExitCode.GeneralError);
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
const tempDir = await mkdtemp(path2.join(tmpdir(), "dodo-profile-"));
|
|
1209
|
+
const filepath = path2.join(tempDir, "profile.md");
|
|
1210
|
+
const initial = `${current2.profile.summary}
|
|
1211
|
+
|
|
1212
|
+
--- safety ---
|
|
1213
|
+
${current2.profile.safety_notes ?? ""}
|
|
1214
|
+
`;
|
|
1215
|
+
try {
|
|
1216
|
+
await _internal.writeFile(filepath, initial);
|
|
1217
|
+
await _internal.runEditor(filepath);
|
|
1218
|
+
const next = await _internal.readEditedFile(filepath);
|
|
1219
|
+
if (next.trim() === initial.trim()) {
|
|
1220
|
+
if (ctx.mode === "json") emitJsonOk({ changed: false });
|
|
1221
|
+
else printLine(colorize(ctx).dim("\uBCC0\uACBD \uC5C6\uC74C."));
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
const { summary, safety_notes } = splitProfileBody(next);
|
|
1225
|
+
const result = await apiRequest(
|
|
1226
|
+
`/api/travel-profiles/${current2.profile.id}`,
|
|
1227
|
+
{
|
|
1228
|
+
method: "PATCH",
|
|
1229
|
+
body: {
|
|
1230
|
+
summary,
|
|
1231
|
+
safety_notes,
|
|
1232
|
+
expected_updated_at: current2.profile.updated_at
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
);
|
|
1236
|
+
if (ctx.mode === "json") emitJsonOk(result);
|
|
1237
|
+
else printLine(colorize(ctx).green("\u2713 \uC800\uC7A5\uB428."));
|
|
1238
|
+
} finally {
|
|
1239
|
+
await _internal.rm(tempDir);
|
|
1240
|
+
}
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
if (err instanceof ApiError) {
|
|
1243
|
+
const isConflict = isProfileConflictError(err);
|
|
1244
|
+
const msg = isConflict ? "\uD504\uB85C\uD544\uC774 \uB2E4\uB978 \uACF3\uC5D0\uC11C \uC218\uC815\uB418\uC5B4 \uBCC0\uACBD\uC744 \uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. `dodo profile show` \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694." : err.message;
|
|
1245
|
+
if (ctx.mode === "json") emitJsonError(isConflict ? "conflict" : "edit_failed", msg);
|
|
1246
|
+
else printError(msg, ctx);
|
|
1247
|
+
process.exit(err.exitCode);
|
|
1248
|
+
return;
|
|
1249
|
+
}
|
|
1250
|
+
if (err instanceof Error) {
|
|
1251
|
+
if (ctx.mode === "json") emitJsonError("editor_error", err.message);
|
|
1252
|
+
else printError(`\uC624\uB958: ${err.message}`, ctx);
|
|
1253
|
+
process.exit(ExitCode.GeneralError);
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
throw err;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
});
|
|
1260
|
+
var clear = defineCommand4({
|
|
1261
|
+
meta: { name: "clear", description: "\uC5EC\uD589 \uD504\uB85C\uD544\uC744 \uC601\uAD6C \uC0AD\uC81C\uD569\uB2C8\uB2E4 (--confirm \uD544\uC218)." },
|
|
1262
|
+
args: {
|
|
1263
|
+
confirm: { type: "boolean", description: "\uBA85\uC2DC \uB3D9\uC758 \u2014 \uC774 \uD50C\uB798\uADF8\uAC00 \uC5C6\uC73C\uBA74 \uAC70\uC808." },
|
|
1264
|
+
locale: { type: "string", description: "ko | en | es | fr" },
|
|
1265
|
+
output: { type: "string", description: "pretty | json" }
|
|
1266
|
+
},
|
|
1267
|
+
async run({ args }) {
|
|
1268
|
+
const ctx = await resolveOutputContext(args.output);
|
|
1269
|
+
if (!args.confirm) {
|
|
1270
|
+
const msg = "\uC774 \uC791\uC5C5\uC740 \uC601\uAD6C \uC0AD\uC81C\uC785\uB2C8\uB2E4. \uC9C4\uD589\uD558\uB824\uBA74 --confirm \uD50C\uB798\uADF8\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.";
|
|
1271
|
+
if (ctx.mode === "json") emitJsonError("confirm_required", msg);
|
|
1272
|
+
else printError(msg, ctx);
|
|
1273
|
+
process.exit(ExitCode.InvalidArgs);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1276
|
+
const locale = await resolveLocale(args.locale);
|
|
1277
|
+
try {
|
|
1278
|
+
const current2 = await executeFunction(
|
|
1279
|
+
"get_travel_profile",
|
|
1280
|
+
{},
|
|
1281
|
+
{ locale }
|
|
1282
|
+
);
|
|
1283
|
+
if (!current2.profile) {
|
|
1284
|
+
if (ctx.mode === "json") emitJsonOk({ ok: true, message: "no profile" });
|
|
1285
|
+
else printLine(colorize(ctx).dim("\uD504\uB85C\uD544\uC774 \uC5C6\uC2B5\uB2C8\uB2E4."));
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
await apiRequest(`/api/travel-profiles/${current2.profile.id}`, {
|
|
1289
|
+
method: "DELETE"
|
|
1290
|
+
});
|
|
1291
|
+
if (ctx.mode === "json") emitJsonOk({ ok: true });
|
|
1292
|
+
else printLine(colorize(ctx).green("\u2713 \uC0AD\uC81C\uB428."));
|
|
1293
|
+
} catch (err) {
|
|
1294
|
+
if (err instanceof ApiError) {
|
|
1295
|
+
if (ctx.mode === "json") emitJsonError("clear_failed", err.message);
|
|
1296
|
+
else printError(err.message, ctx);
|
|
1297
|
+
process.exit(err.exitCode);
|
|
1298
|
+
return;
|
|
1299
|
+
}
|
|
1300
|
+
throw err;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
});
|
|
1304
|
+
function renderFinalizeCard(draft, opts) {
|
|
1305
|
+
const c = colorize({ mode: "pretty", color: opts.color });
|
|
1306
|
+
const lines = [];
|
|
1307
|
+
lines.push(c.bold("\u2500\u2500\u2500 \uC5EC\uD589 \uD504\uB85C\uD544 \uC81C\uC548 \u2500\u2500\u2500"));
|
|
1308
|
+
lines.push(c.bold("\uC694\uC57D:"));
|
|
1309
|
+
lines.push(draft.summary);
|
|
1310
|
+
if (draft.safety_notes && draft.safety_notes.trim()) {
|
|
1311
|
+
lines.push("");
|
|
1312
|
+
lines.push(c.bold("\uC548\uC804 \uB178\uD2B8:"));
|
|
1313
|
+
lines.push(draft.safety_notes);
|
|
1314
|
+
}
|
|
1315
|
+
lines.push(c.dim("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
1316
|
+
return lines;
|
|
1317
|
+
}
|
|
1318
|
+
function confirmFinalizeAction(input) {
|
|
1319
|
+
const v = input.trim().toLowerCase();
|
|
1320
|
+
if (v === "y" || v === "yes") return "save";
|
|
1321
|
+
if (v === "e" || v === "edit") return "edit";
|
|
1322
|
+
return "cancel";
|
|
1323
|
+
}
|
|
1324
|
+
async function* parseSseStream(response) {
|
|
1325
|
+
if (!response.body) return;
|
|
1326
|
+
const reader = response.body.getReader();
|
|
1327
|
+
const decoder = new TextDecoder();
|
|
1328
|
+
let buffer = "";
|
|
1329
|
+
while (true) {
|
|
1330
|
+
const { value, done } = await reader.read();
|
|
1331
|
+
if (done) break;
|
|
1332
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1333
|
+
let separator;
|
|
1334
|
+
while ((separator = buffer.indexOf("\n\n")) !== -1) {
|
|
1335
|
+
const block = buffer.slice(0, separator);
|
|
1336
|
+
buffer = buffer.slice(separator + 2);
|
|
1337
|
+
let event = "message";
|
|
1338
|
+
let dataStr = "";
|
|
1339
|
+
for (const line of block.split("\n")) {
|
|
1340
|
+
if (line.startsWith("event:")) event = line.slice(6).trim();
|
|
1341
|
+
else if (line.startsWith("data:")) dataStr += line.slice(5).trim();
|
|
1342
|
+
}
|
|
1343
|
+
if (!event) continue;
|
|
1344
|
+
let data = {};
|
|
1345
|
+
try {
|
|
1346
|
+
data = dataStr ? JSON.parse(dataStr) : {};
|
|
1347
|
+
} catch {
|
|
1348
|
+
}
|
|
1349
|
+
yield { event, data };
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
async function streamProfileBuilderTurn(history, opts) {
|
|
1354
|
+
const config = await readConfig();
|
|
1355
|
+
const token = await getToken();
|
|
1356
|
+
if (!token) {
|
|
1357
|
+
throw new ApiError(
|
|
1358
|
+
"\uC778\uC99D\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. `dodo auth login` \uC73C\uB85C \uD1A0\uD070\uC744 \uB4F1\uB85D\uD558\uC138\uC694.",
|
|
1359
|
+
401,
|
|
1360
|
+
ExitCode.Unauthorized
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
const url = new URL("/api/cli/chat", config.apiUrl).toString();
|
|
1364
|
+
let response;
|
|
1365
|
+
try {
|
|
1366
|
+
response = await fetch(url, {
|
|
1367
|
+
method: "POST",
|
|
1368
|
+
headers: {
|
|
1369
|
+
authorization: `Bearer ${token}`,
|
|
1370
|
+
"content-type": "application/json",
|
|
1371
|
+
accept: "text/event-stream"
|
|
1372
|
+
},
|
|
1373
|
+
body: JSON.stringify({
|
|
1374
|
+
messages: history,
|
|
1375
|
+
locale: opts.locale,
|
|
1376
|
+
mode: "profile_builder"
|
|
1377
|
+
})
|
|
1378
|
+
});
|
|
1379
|
+
} catch (err) {
|
|
1380
|
+
const msg = err instanceof Error ? err.message : "network error";
|
|
1381
|
+
throw new ApiError(`\uC11C\uBC84\uC5D0 \uC5F0\uACB0\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4: ${msg}`, 0, ExitCode.Network);
|
|
1382
|
+
}
|
|
1383
|
+
if (!response.ok) {
|
|
1384
|
+
const body = await response.text().catch(() => "");
|
|
1385
|
+
let parsed = {};
|
|
1386
|
+
try {
|
|
1387
|
+
parsed = JSON.parse(body);
|
|
1388
|
+
} catch {
|
|
1389
|
+
}
|
|
1390
|
+
throw new ApiError(
|
|
1391
|
+
parsed.error ?? `HTTP ${response.status}`,
|
|
1392
|
+
response.status,
|
|
1393
|
+
exitCodeForStatus(response.status)
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
let reply = "";
|
|
1397
|
+
let finalizeDraft = null;
|
|
1398
|
+
for await (const evt of parseSseStream(response)) {
|
|
1399
|
+
if (evt.event === "text") {
|
|
1400
|
+
const t = evt.data.text;
|
|
1401
|
+
if (t) {
|
|
1402
|
+
process.stdout.write(t);
|
|
1403
|
+
reply += t;
|
|
1404
|
+
}
|
|
1405
|
+
} else if (evt.event === "tool" && evt.data.name === "finalize_travel_profile") {
|
|
1406
|
+
const result = evt.data.result;
|
|
1407
|
+
if (result?.ok && result.draft) finalizeDraft = result.draft;
|
|
1408
|
+
} else if (evt.event === "done") {
|
|
1409
|
+
process.stdout.write("\n");
|
|
1410
|
+
break;
|
|
1411
|
+
} else if (evt.event === "error") {
|
|
1412
|
+
const message = String(evt.data.message ?? "stream error");
|
|
1413
|
+
throw new ApiError(message, 0, ExitCode.GeneralError);
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
return { reply, finalizeDraft };
|
|
1417
|
+
}
|
|
1418
|
+
function isProfileConflictError(err) {
|
|
1419
|
+
if (!(err instanceof ApiError)) return false;
|
|
1420
|
+
if (err.status === 409) return true;
|
|
1421
|
+
return /Conflict|409|expected_updated_at/i.test(err.message);
|
|
1422
|
+
}
|
|
1423
|
+
async function saveProfileDraft(draft, snapshot) {
|
|
1424
|
+
if (snapshot.profile) {
|
|
1425
|
+
await apiRequest(`/api/travel-profiles/${snapshot.profile.id}`, {
|
|
1426
|
+
method: "PATCH",
|
|
1427
|
+
body: {
|
|
1428
|
+
summary: draft.summary,
|
|
1429
|
+
safety_notes: draft.safety_notes,
|
|
1430
|
+
expected_updated_at: snapshot.profile.updated_at
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
} else {
|
|
1434
|
+
await apiRequest("/api/travel-profiles", {
|
|
1435
|
+
method: "POST",
|
|
1436
|
+
body: {
|
|
1437
|
+
summary: draft.summary,
|
|
1438
|
+
safety_notes: draft.safety_notes
|
|
1439
|
+
}
|
|
1440
|
+
});
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
async function editDraftInEditor(draft) {
|
|
1444
|
+
const tempDir = await mkdtemp(path2.join(tmpdir(), "dodo-profile-draft-"));
|
|
1445
|
+
const filepath = path2.join(tempDir, "draft.md");
|
|
1446
|
+
try {
|
|
1447
|
+
await _internal.writeFile(
|
|
1448
|
+
filepath,
|
|
1449
|
+
`${draft.summary}
|
|
1450
|
+
|
|
1451
|
+
--- safety ---
|
|
1452
|
+
${draft.safety_notes}
|
|
1453
|
+
`
|
|
1454
|
+
);
|
|
1455
|
+
await _internal.runEditor(filepath);
|
|
1456
|
+
return splitProfileBody(await _internal.readEditedFile(filepath));
|
|
1457
|
+
} finally {
|
|
1458
|
+
await _internal.rm(tempDir);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
var chat = defineCommand4({
|
|
1462
|
+
meta: { name: "chat", description: "\uC5EC\uD589 \uD504\uB85C\uD544 \uBE4C\uB354 \u2014 \uD14D\uC2A4\uD2B8 REPL." },
|
|
1463
|
+
args: {
|
|
1464
|
+
locale: { type: "string", description: "ko | en | es | fr" },
|
|
1465
|
+
output: { type: "string", description: "pretty | json" }
|
|
1466
|
+
},
|
|
1467
|
+
async run({ args }) {
|
|
1468
|
+
const ctx = await resolveOutputContext(args.output);
|
|
1469
|
+
if (ctx.mode === "json") {
|
|
1470
|
+
emitJsonError("non_json", "REPL \uBA85\uB839\uC740 pretty \uBAA8\uB4DC\uB9CC \uC9C0\uC6D0\uD569\uB2C8\uB2E4.");
|
|
1471
|
+
process.exit(ExitCode.InvalidArgs);
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
if (!isInteractive()) {
|
|
1475
|
+
printError("\uD130\uBBF8\uB110 \uBE44\uB300\uD654 \uD658\uACBD\uC5D0\uC11C\uB294 REPL\uC744 \uC2DC\uC791\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", ctx);
|
|
1476
|
+
process.exit(ExitCode.InvalidArgs);
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
const locale = await resolveLocale(args.locale);
|
|
1480
|
+
const c = colorize(ctx);
|
|
1481
|
+
printLine(c.dim("\uD504\uB85C\uD544 \uBE4C\uB354\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4. \uC885\uB8CC\uD558\uB824\uBA74 :q"));
|
|
1482
|
+
let initialSnapshot;
|
|
1483
|
+
try {
|
|
1484
|
+
initialSnapshot = await executeFunction(
|
|
1485
|
+
"get_travel_profile",
|
|
1486
|
+
{},
|
|
1487
|
+
{ locale }
|
|
1488
|
+
);
|
|
1489
|
+
} catch (err) {
|
|
1490
|
+
if (err instanceof ApiError) {
|
|
1491
|
+
printError(err.message, ctx);
|
|
1492
|
+
process.exit(err.exitCode);
|
|
1493
|
+
return;
|
|
1494
|
+
}
|
|
1495
|
+
throw err;
|
|
1496
|
+
}
|
|
1497
|
+
const history = [];
|
|
1498
|
+
while (true) {
|
|
1499
|
+
const userInput = await text2("you> ");
|
|
1500
|
+
if (userInput === null) break;
|
|
1501
|
+
const trimmed = userInput.trim();
|
|
1502
|
+
if (trimmed === ":q") break;
|
|
1503
|
+
if (!trimmed) continue;
|
|
1504
|
+
history.push({ role: "user", text: trimmed });
|
|
1505
|
+
try {
|
|
1506
|
+
const { reply, finalizeDraft } = await streamProfileBuilderTurn(history, { locale });
|
|
1507
|
+
history.push({ role: "model", text: reply });
|
|
1508
|
+
if (finalizeDraft) {
|
|
1509
|
+
for (const line of renderFinalizeCard(finalizeDraft, { color: ctx.color })) {
|
|
1510
|
+
printLine(line);
|
|
1511
|
+
}
|
|
1512
|
+
const choice = await text2("[y]es / [N]o / [e]dit > ");
|
|
1513
|
+
const action = confirmFinalizeAction(choice ?? "");
|
|
1514
|
+
if (action === "save") {
|
|
1515
|
+
try {
|
|
1516
|
+
await saveProfileDraft(finalizeDraft, initialSnapshot);
|
|
1517
|
+
printLine(c.green("\u2713 \uC800\uC7A5\uB428."));
|
|
1518
|
+
} catch (saveErr) {
|
|
1519
|
+
if (isProfileConflictError(saveErr)) {
|
|
1520
|
+
printError(
|
|
1521
|
+
"\uD504\uB85C\uD544\uC774 \uB2E4\uB978 \uACF3\uC5D0\uC11C \uC218\uC815\uB418\uC5B4 \uBCC0\uACBD\uC744 \uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. `dodo profile show` \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.",
|
|
1522
|
+
ctx
|
|
1523
|
+
);
|
|
1524
|
+
process.exit(ExitCode.GeneralError);
|
|
1525
|
+
return;
|
|
1526
|
+
}
|
|
1527
|
+
throw saveErr;
|
|
1528
|
+
}
|
|
1529
|
+
break;
|
|
1530
|
+
} else if (action === "edit") {
|
|
1531
|
+
const edited = await editDraftInEditor(finalizeDraft);
|
|
1532
|
+
try {
|
|
1533
|
+
await saveProfileDraft(edited, initialSnapshot);
|
|
1534
|
+
printLine(c.green("\u2713 \uC800\uC7A5\uB428 (\uC218\uC815\uBCF8)."));
|
|
1535
|
+
} catch (saveErr) {
|
|
1536
|
+
if (isProfileConflictError(saveErr)) {
|
|
1537
|
+
printError(
|
|
1538
|
+
"\uD504\uB85C\uD544\uC774 \uB2E4\uB978 \uACF3\uC5D0\uC11C \uC218\uC815\uB418\uC5B4 \uBCC0\uACBD\uC744 \uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. `dodo profile show` \uD6C4 \uB2E4\uC2DC \uC2DC\uB3C4\uD558\uC138\uC694.",
|
|
1539
|
+
ctx
|
|
1540
|
+
);
|
|
1541
|
+
process.exit(ExitCode.GeneralError);
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
throw saveErr;
|
|
1545
|
+
}
|
|
1546
|
+
break;
|
|
1547
|
+
} else {
|
|
1548
|
+
printLine(c.dim("\uCDE8\uC18C. \uB300\uD654\uB97C \uACC4\uC18D\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4."));
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
} catch (err) {
|
|
1552
|
+
if (err instanceof ApiError) {
|
|
1553
|
+
printError(err.message, ctx);
|
|
1554
|
+
process.exit(err.exitCode);
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
if (err instanceof Error) {
|
|
1558
|
+
printError(`\uC624\uB958: ${err.message}`, ctx);
|
|
1559
|
+
process.exit(ExitCode.GeneralError);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
throw err;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
});
|
|
1567
|
+
var profileCommand = defineCommand4({
|
|
1568
|
+
meta: { name: "profile", description: "\uC5EC\uD589 \uD504\uB85C\uD544 (show/toggle/edit/clear/chat)." },
|
|
1569
|
+
subCommands: { show, toggle, edit, clear, chat }
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1032
1572
|
// src/commands/expense.ts
|
|
1033
1573
|
init_api_client();
|
|
1034
1574
|
init_exit_codes();
|
|
1035
1575
|
init_output();
|
|
1036
1576
|
init_config();
|
|
1037
1577
|
init_state();
|
|
1038
|
-
import { defineCommand as
|
|
1578
|
+
import { defineCommand as defineCommand5 } from "citty";
|
|
1039
1579
|
async function resolveTripId(flagTrip, ctx) {
|
|
1040
1580
|
const direct = await getActiveTripId(flagTrip);
|
|
1041
1581
|
if (direct) return direct;
|
|
@@ -1054,7 +1594,7 @@ async function resolveTripId(flagTrip, ctx) {
|
|
|
1054
1594
|
}
|
|
1055
1595
|
return state.activeTrip.id;
|
|
1056
1596
|
}
|
|
1057
|
-
var list2 =
|
|
1597
|
+
var list2 = defineCommand5({
|
|
1058
1598
|
meta: { name: "list", description: "\uD65C\uC131 trip\uC758 \uACBD\uBE44 \uBAA9\uB85D\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4." },
|
|
1059
1599
|
args: {
|
|
1060
1600
|
limit: { type: "string", description: "\uCD5C\uB300 \uD45C\uC2DC \uAC74\uC218 (\uAE30\uBCF8 20)" },
|
|
@@ -1105,7 +1645,7 @@ var list2 = defineCommand4({
|
|
|
1105
1645
|
}
|
|
1106
1646
|
}
|
|
1107
1647
|
});
|
|
1108
|
-
var add =
|
|
1648
|
+
var add = defineCommand5({
|
|
1109
1649
|
meta: { name: "add", description: "\uACBD\uBE44\uB97C \uCD94\uAC00\uD569\uB2C8\uB2E4." },
|
|
1110
1650
|
args: {
|
|
1111
1651
|
amount: { type: "string", description: "\uAE08\uC561 (\uC22B\uC790)", required: true },
|
|
@@ -1143,7 +1683,8 @@ var add = defineCommand4({
|
|
|
1143
1683
|
amount: String(amount),
|
|
1144
1684
|
currency: args.currency,
|
|
1145
1685
|
description: args.description,
|
|
1146
|
-
|
|
1686
|
+
// 서버 router는 args.expense_type을 읽음 (router.ts:125)
|
|
1687
|
+
expense_type: type,
|
|
1147
1688
|
category: args.category,
|
|
1148
1689
|
date: args.date
|
|
1149
1690
|
},
|
|
@@ -1161,7 +1702,7 @@ var add = defineCommand4({
|
|
|
1161
1702
|
}
|
|
1162
1703
|
}
|
|
1163
1704
|
});
|
|
1164
|
-
var update =
|
|
1705
|
+
var update = defineCommand5({
|
|
1165
1706
|
meta: { name: "update", description: "\uACBD\uBE44\uB97C \uC218\uC815\uD569\uB2C8\uB2E4." },
|
|
1166
1707
|
args: {
|
|
1167
1708
|
id: { type: "positional", description: "\uACBD\uBE44 ID", required: true },
|
|
@@ -1183,11 +1724,13 @@ var update = defineCommand4({
|
|
|
1183
1724
|
const result = await executeFunction(
|
|
1184
1725
|
"update_expense",
|
|
1185
1726
|
{
|
|
1186
|
-
|
|
1727
|
+
// 서버 router는 args.expense_id를 읽음 (router.ts:197)
|
|
1728
|
+
expense_id: args.id,
|
|
1187
1729
|
amount: args.amount,
|
|
1188
1730
|
currency: args.currency,
|
|
1189
1731
|
description: args.description,
|
|
1190
|
-
|
|
1732
|
+
// 서버 router는 args.expense_type을 읽지 않음 — update는 type 변경 미지원
|
|
1733
|
+
// (router.ts:191-208에 expense_type 호출 없음). 본 인자는 의도적으로 미전송.
|
|
1191
1734
|
category: args.category,
|
|
1192
1735
|
date: args.date
|
|
1193
1736
|
},
|
|
@@ -1205,7 +1748,7 @@ var update = defineCommand4({
|
|
|
1205
1748
|
}
|
|
1206
1749
|
}
|
|
1207
1750
|
});
|
|
1208
|
-
var del =
|
|
1751
|
+
var del = defineCommand5({
|
|
1209
1752
|
meta: { name: "delete", description: "\uACBD\uBE44\uB97C \uC0AD\uC81C\uD569\uB2C8\uB2E4 (--yes \uC5C6\uC73C\uBA74 confirm)." },
|
|
1210
1753
|
args: {
|
|
1211
1754
|
id: { type: "positional", description: "\uACBD\uBE44 ID", required: true },
|
|
@@ -1218,7 +1761,8 @@ var del = defineCommand4({
|
|
|
1218
1761
|
const { runFunctionCommand: runFunctionCommand2 } = await Promise.resolve().then(() => (init_command_helpers(), command_helpers_exports));
|
|
1219
1762
|
await runFunctionCommand2({
|
|
1220
1763
|
function: "delete_expense",
|
|
1221
|
-
|
|
1764
|
+
// 서버 router는 args.expense_id를 읽음 (router.ts:210)
|
|
1765
|
+
args: { expense_id: args.id },
|
|
1222
1766
|
outputFlag: args.output,
|
|
1223
1767
|
localeFlag: args.locale,
|
|
1224
1768
|
tripFlag: args.trip,
|
|
@@ -1227,7 +1771,7 @@ var del = defineCommand4({
|
|
|
1227
1771
|
});
|
|
1228
1772
|
}
|
|
1229
1773
|
});
|
|
1230
|
-
var expenseCommand =
|
|
1774
|
+
var expenseCommand = defineCommand5({
|
|
1231
1775
|
meta: { name: "expense", description: "\uACBD\uBE44 \uAD00\uB9AC (list/add/update/delete)." },
|
|
1232
1776
|
subCommands: { list: list2, add, update, delete: del }
|
|
1233
1777
|
});
|
|
@@ -1235,8 +1779,8 @@ var expenseCommand = defineCommand4({
|
|
|
1235
1779
|
// src/commands/booking.ts
|
|
1236
1780
|
init_command_helpers();
|
|
1237
1781
|
init_output();
|
|
1238
|
-
import { defineCommand as
|
|
1239
|
-
var list3 =
|
|
1782
|
+
import { defineCommand as defineCommand6 } from "citty";
|
|
1783
|
+
var list3 = defineCommand6({
|
|
1240
1784
|
meta: { name: "list", description: "\uD65C\uC131 trip\uC758 \uC608\uC57D \uBAA9\uB85D." },
|
|
1241
1785
|
args: {
|
|
1242
1786
|
type: { type: "string", description: "flight|train|accommodation|activity|car_rental|transfer" },
|
|
@@ -1273,7 +1817,7 @@ var list3 = defineCommand5({
|
|
|
1273
1817
|
});
|
|
1274
1818
|
}
|
|
1275
1819
|
});
|
|
1276
|
-
var add2 =
|
|
1820
|
+
var add2 = defineCommand6({
|
|
1277
1821
|
meta: { name: "add", description: "\uC608\uC57D \uCD94\uAC00." },
|
|
1278
1822
|
args: {
|
|
1279
1823
|
type: { type: "string", required: true, description: "flight|train|accommodation|activity|car_rental|transfer" },
|
|
@@ -1301,15 +1845,19 @@ var add2 = defineCommand5({
|
|
|
1301
1845
|
}
|
|
1302
1846
|
await runFunctionCommand({
|
|
1303
1847
|
function: "add_booking",
|
|
1848
|
+
// 서버 router(router.ts:129-178)는 다음 args 키를 읽는다:
|
|
1849
|
+
// args.type, args.title, args.date, args.notes, args.booking_scope,
|
|
1850
|
+
// + 다양한 detail 키 (flight_number, check_in, hotel_name 등)
|
|
1851
|
+
// 다음 CLI 플래그는 서버 함수 시그니처에 대응 인자가 없어 무시된다:
|
|
1852
|
+
// --vendor, --amount, --currency, --end-date
|
|
1853
|
+
// 따라서 dispatched args에서 제외해 false-pretend("성공"인데 데이터 누락)을 막는다.
|
|
1854
|
+
// --start-date는 서버의 단일 `date` 필드로 매핑 (시작일이 booking_date의 의미와 부합).
|
|
1855
|
+
// 추후 서버가 vendor/amount/currency/end_date를 지원하게 되면 args 추가.
|
|
1304
1856
|
args: {
|
|
1305
1857
|
type: args.type,
|
|
1306
1858
|
title: args.title,
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
end_date: args["end-date"],
|
|
1310
|
-
vendor: args.vendor,
|
|
1311
|
-
amount: args.amount,
|
|
1312
|
-
currency: args.currency,
|
|
1859
|
+
booking_scope: args.scope ?? "shared",
|
|
1860
|
+
date: args["start-date"],
|
|
1313
1861
|
...extraArgs
|
|
1314
1862
|
},
|
|
1315
1863
|
outputFlag: args.output,
|
|
@@ -1319,7 +1867,7 @@ var add2 = defineCommand5({
|
|
|
1319
1867
|
});
|
|
1320
1868
|
}
|
|
1321
1869
|
});
|
|
1322
|
-
var update2 =
|
|
1870
|
+
var update2 = defineCommand6({
|
|
1323
1871
|
meta: { name: "update", description: "\uC608\uC57D \uC218\uC815." },
|
|
1324
1872
|
args: {
|
|
1325
1873
|
id: { type: "positional", required: true, description: "\uC608\uC57D ID" },
|
|
@@ -1346,14 +1894,13 @@ var update2 = defineCommand5({
|
|
|
1346
1894
|
}
|
|
1347
1895
|
await runFunctionCommand({
|
|
1348
1896
|
function: "update_booking",
|
|
1897
|
+
// 서버 router(router.ts:211-258)는 args.booking_id, args.title, args.date,
|
|
1898
|
+
// args.notes 외 detailsInput용 detail 키들을 읽는다. add_booking과 동일 이유로
|
|
1899
|
+
// --vendor/--amount/--currency/--end-date는 미지원 — dispatched args 제외.
|
|
1349
1900
|
args: {
|
|
1350
|
-
|
|
1901
|
+
booking_id: args.id,
|
|
1351
1902
|
title: args.title,
|
|
1352
|
-
|
|
1353
|
-
end_date: args["end-date"],
|
|
1354
|
-
vendor: args.vendor,
|
|
1355
|
-
amount: args.amount,
|
|
1356
|
-
currency: args.currency,
|
|
1903
|
+
date: args["start-date"],
|
|
1357
1904
|
...extraArgs
|
|
1358
1905
|
},
|
|
1359
1906
|
outputFlag: args.output,
|
|
@@ -1363,7 +1910,7 @@ var update2 = defineCommand5({
|
|
|
1363
1910
|
});
|
|
1364
1911
|
}
|
|
1365
1912
|
});
|
|
1366
|
-
var del2 =
|
|
1913
|
+
var del2 = defineCommand6({
|
|
1367
1914
|
meta: { name: "delete", description: "\uC608\uC57D \uC0AD\uC81C." },
|
|
1368
1915
|
args: {
|
|
1369
1916
|
id: { type: "positional", required: true, description: "\uC608\uC57D ID" },
|
|
@@ -1375,7 +1922,8 @@ var del2 = defineCommand5({
|
|
|
1375
1922
|
async run({ args }) {
|
|
1376
1923
|
await runFunctionCommand({
|
|
1377
1924
|
function: "delete_booking",
|
|
1378
|
-
|
|
1925
|
+
// 서버 router는 args.booking_id를 읽음 (declarations.ts의 delete_booking)
|
|
1926
|
+
args: { booking_id: args.id },
|
|
1379
1927
|
outputFlag: args.output,
|
|
1380
1928
|
localeFlag: args.locale,
|
|
1381
1929
|
tripFlag: args.trip,
|
|
@@ -1384,7 +1932,7 @@ var del2 = defineCommand5({
|
|
|
1384
1932
|
});
|
|
1385
1933
|
}
|
|
1386
1934
|
});
|
|
1387
|
-
var bookingCommand =
|
|
1935
|
+
var bookingCommand = defineCommand6({
|
|
1388
1936
|
meta: { name: "booking", description: "\uC608\uC57D \uAD00\uB9AC." },
|
|
1389
1937
|
subCommands: { list: list3, add: add2, update: update2, delete: del2 }
|
|
1390
1938
|
});
|
|
@@ -1392,8 +1940,8 @@ var bookingCommand = defineCommand5({
|
|
|
1392
1940
|
// src/commands/itinerary.ts
|
|
1393
1941
|
init_command_helpers();
|
|
1394
1942
|
init_output();
|
|
1395
|
-
import { defineCommand as
|
|
1396
|
-
var
|
|
1943
|
+
import { defineCommand as defineCommand7 } from "citty";
|
|
1944
|
+
var show2 = defineCommand7({
|
|
1397
1945
|
meta: { name: "show", description: "\uC77C\uC815 \uD45C\uC2DC." },
|
|
1398
1946
|
args: {
|
|
1399
1947
|
date: { type: "string", description: "YYYY-MM-DD (\uD2B9\uC815 \uB0A0\uB9CC)" },
|
|
@@ -1422,7 +1970,7 @@ var show = defineCommand6({
|
|
|
1422
1970
|
});
|
|
1423
1971
|
}
|
|
1424
1972
|
});
|
|
1425
|
-
var add3 =
|
|
1973
|
+
var add3 = defineCommand7({
|
|
1426
1974
|
meta: { name: "add", description: "\uC77C\uC815\uC5D0 \uC7A5\uC18C \uCD94\uAC00." },
|
|
1427
1975
|
args: {
|
|
1428
1976
|
date: { type: "string", required: true, description: "YYYY-MM-DD" },
|
|
@@ -1444,7 +1992,7 @@ var add3 = defineCommand6({
|
|
|
1444
1992
|
});
|
|
1445
1993
|
}
|
|
1446
1994
|
});
|
|
1447
|
-
var remove =
|
|
1995
|
+
var remove = defineCommand7({
|
|
1448
1996
|
meta: { name: "remove", description: "\uC77C\uC815\uC5D0\uC11C \uC7A5\uC18C \uC0AD\uC81C." },
|
|
1449
1997
|
args: {
|
|
1450
1998
|
date: { type: "string", required: true, description: "YYYY-MM-DD" },
|
|
@@ -1466,7 +2014,7 @@ var remove = defineCommand6({
|
|
|
1466
2014
|
});
|
|
1467
2015
|
}
|
|
1468
2016
|
});
|
|
1469
|
-
var reorder =
|
|
2017
|
+
var reorder = defineCommand7({
|
|
1470
2018
|
meta: { name: "reorder", description: "\uC77C\uC815 \uC21C\uC11C \uBCC0\uACBD." },
|
|
1471
2019
|
args: {
|
|
1472
2020
|
date: { type: "string", required: true, description: "YYYY-MM-DD" },
|
|
@@ -1487,16 +2035,16 @@ var reorder = defineCommand6({
|
|
|
1487
2035
|
});
|
|
1488
2036
|
}
|
|
1489
2037
|
});
|
|
1490
|
-
var itineraryCommand =
|
|
2038
|
+
var itineraryCommand = defineCommand7({
|
|
1491
2039
|
meta: { name: "itinerary", description: "\uC77C\uC815 \uAD00\uB9AC." },
|
|
1492
|
-
subCommands: { show, add: add3, remove, reorder }
|
|
2040
|
+
subCommands: { show: show2, add: add3, remove, reorder }
|
|
1493
2041
|
});
|
|
1494
2042
|
|
|
1495
2043
|
// src/commands/search.ts
|
|
1496
2044
|
init_command_helpers();
|
|
1497
2045
|
init_output();
|
|
1498
|
-
import { defineCommand as
|
|
1499
|
-
var flightSearch =
|
|
2046
|
+
import { defineCommand as defineCommand8 } from "citty";
|
|
2047
|
+
var flightSearch = defineCommand8({
|
|
1500
2048
|
meta: { name: "search", description: "\uD56D\uACF5\uD3B8 \uAC80\uC0C9 (Amadeus)." },
|
|
1501
2049
|
args: {
|
|
1502
2050
|
from: { type: "string", required: true, description: "\uCD9C\uBC1C IATA (\uC608: ICN)" },
|
|
@@ -1535,7 +2083,7 @@ var flightSearch = defineCommand7({
|
|
|
1535
2083
|
});
|
|
1536
2084
|
}
|
|
1537
2085
|
});
|
|
1538
|
-
var hotelSearch =
|
|
2086
|
+
var hotelSearch = defineCommand8({
|
|
1539
2087
|
meta: { name: "search", description: "\uD638\uD154 \uAC80\uC0C9 (Amadeus)." },
|
|
1540
2088
|
args: {
|
|
1541
2089
|
city: { type: "string", required: true, description: "\uB3C4\uC2DC IATA \uB610\uB294 \uC774\uB984" },
|
|
@@ -1551,7 +2099,9 @@ var hotelSearch = defineCommand7({
|
|
|
1551
2099
|
await runFunctionCommand({
|
|
1552
2100
|
function: "search_hotels",
|
|
1553
2101
|
args: {
|
|
1554
|
-
|
|
2102
|
+
// 서버 router는 args.city_code를 읽음 (router.ts:81). CLI --city 플래그명은
|
|
2103
|
+
// 사용자 친화 표기로 유지하되, 서버에 보낼 때 키를 정정한다.
|
|
2104
|
+
city_code: args.city,
|
|
1555
2105
|
check_in_date: args["check-in"],
|
|
1556
2106
|
check_out_date: args["check-out"],
|
|
1557
2107
|
adults: args.adults ?? "2",
|
|
@@ -1569,7 +2119,7 @@ var hotelSearch = defineCommand7({
|
|
|
1569
2119
|
});
|
|
1570
2120
|
}
|
|
1571
2121
|
});
|
|
1572
|
-
var activitySearch =
|
|
2122
|
+
var activitySearch = defineCommand8({
|
|
1573
2123
|
meta: { name: "search", description: "\uC561\uD2F0\uBE44\uD2F0 \uAC80\uC0C9 (Amadeus)." },
|
|
1574
2124
|
args: {
|
|
1575
2125
|
city: { type: "string", required: true, description: "\uB3C4\uC2DC \uC774\uB984" },
|
|
@@ -1594,7 +2144,7 @@ var activitySearch = defineCommand7({
|
|
|
1594
2144
|
});
|
|
1595
2145
|
}
|
|
1596
2146
|
});
|
|
1597
|
-
var transferSearch =
|
|
2147
|
+
var transferSearch = defineCommand8({
|
|
1598
2148
|
meta: { name: "search", description: "\uAD50\uD1B5\uD3B8 \uAC80\uC0C9 (Amadeus, \uACF5\uD56D-\uC8FC\uC18C \uD53D\uC5C5 \uB4F1)." },
|
|
1599
2149
|
args: {
|
|
1600
2150
|
"start-time": { type: "string", required: true, description: "\uCD9C\uBC1C \uC2DC\uAC01 ISO" },
|
|
@@ -1620,12 +2170,19 @@ var transferSearch = defineCommand7({
|
|
|
1620
2170
|
}
|
|
1621
2171
|
await runFunctionCommand({
|
|
1622
2172
|
function: "search_transfers",
|
|
2173
|
+
// 서버 router(router.ts:89-100)는 다음 키를 읽는다:
|
|
2174
|
+
// args.start_date_time, args.origin_iata, args.origin_address,
|
|
2175
|
+
// args.destination_address, args.destination_place_id,
|
|
2176
|
+
// args.transfer_type, args.passengers, args.currency
|
|
2177
|
+
// CLI 플래그명(--start-time, --from-*, --to-*)은 사용자 친화 표기로 유지하되,
|
|
2178
|
+
// 서버 전송 키를 router 시그니처에 맞춰 정정한다.
|
|
2179
|
+
// 주의: --to-iata는 서버에 destination IATA 인자가 없어 destination_place_id로
|
|
2180
|
+
// 매핑할 수 없다. 보존되지 않으므로 dispatched args에서 제외.
|
|
1623
2181
|
args: {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
to_address: args["to-address"],
|
|
2182
|
+
start_date_time: args["start-time"],
|
|
2183
|
+
origin_iata: args["from-iata"],
|
|
2184
|
+
origin_address: args["from-address"],
|
|
2185
|
+
destination_address: args["to-address"],
|
|
1629
2186
|
passengers: args.passengers ?? "1",
|
|
1630
2187
|
...extraArgs
|
|
1631
2188
|
},
|
|
@@ -1641,19 +2198,19 @@ var transferSearch = defineCommand7({
|
|
|
1641
2198
|
});
|
|
1642
2199
|
}
|
|
1643
2200
|
});
|
|
1644
|
-
var flightCommand =
|
|
2201
|
+
var flightCommand = defineCommand8({
|
|
1645
2202
|
meta: { name: "flight", description: "\uD56D\uACF5\uD3B8 \uAC80\uC0C9 / \uC0C1\uD0DC \uC870\uD68C." },
|
|
1646
2203
|
subCommands: { search: flightSearch }
|
|
1647
2204
|
});
|
|
1648
|
-
var hotelCommand =
|
|
2205
|
+
var hotelCommand = defineCommand8({
|
|
1649
2206
|
meta: { name: "hotel", description: "\uD638\uD154 \uAC80\uC0C9." },
|
|
1650
2207
|
subCommands: { search: hotelSearch }
|
|
1651
2208
|
});
|
|
1652
|
-
var activityCommand =
|
|
2209
|
+
var activityCommand = defineCommand8({
|
|
1653
2210
|
meta: { name: "activity", description: "\uC561\uD2F0\uBE44\uD2F0 \uAC80\uC0C9." },
|
|
1654
2211
|
subCommands: { search: activitySearch }
|
|
1655
2212
|
});
|
|
1656
|
-
var transferCommand =
|
|
2213
|
+
var transferCommand = defineCommand8({
|
|
1657
2214
|
meta: { name: "transfer", description: "\uAD50\uD1B5\uD3B8 \uAC80\uC0C9." },
|
|
1658
2215
|
subCommands: { search: transferSearch }
|
|
1659
2216
|
});
|
|
@@ -1661,8 +2218,8 @@ var transferCommand = defineCommand7({
|
|
|
1661
2218
|
// src/commands/travel.ts
|
|
1662
2219
|
init_command_helpers();
|
|
1663
2220
|
init_output();
|
|
1664
|
-
import { defineCommand as
|
|
1665
|
-
var placeSearch =
|
|
2221
|
+
import { defineCommand as defineCommand9 } from "citty";
|
|
2222
|
+
var placeSearch = defineCommand9({
|
|
1666
2223
|
meta: { name: "search", description: "\uC7A5\uC18C \uAC80\uC0C9 (Google Places, \uB3C4\uC2DC \uB610\uB294 \uD604\uC7AC \uC704\uCE58 \uAE30\uC900)." },
|
|
1667
2224
|
args: {
|
|
1668
2225
|
query: { type: "positional", required: true, description: "\uAC80\uC0C9\uC5B4 \uB610\uB294 \uC7A5\uC18C \uC720\uD615" },
|
|
@@ -1688,7 +2245,7 @@ var placeSearch = defineCommand8({
|
|
|
1688
2245
|
});
|
|
1689
2246
|
}
|
|
1690
2247
|
});
|
|
1691
|
-
var placeSearchText =
|
|
2248
|
+
var placeSearchText = defineCommand9({
|
|
1692
2249
|
meta: { name: "search-text", description: "\uD14D\uC2A4\uD2B8 \uAC80\uC0C9 (\uB3C4\uC2DC \uBC94\uC704)." },
|
|
1693
2250
|
args: {
|
|
1694
2251
|
query: { type: "positional", required: true, description: "\uAC80\uC0C9\uC5B4" },
|
|
@@ -1712,7 +2269,7 @@ var placeSearchText = defineCommand8({
|
|
|
1712
2269
|
});
|
|
1713
2270
|
}
|
|
1714
2271
|
});
|
|
1715
|
-
var placeDetails =
|
|
2272
|
+
var placeDetails = defineCommand9({
|
|
1716
2273
|
meta: { name: "details", description: "\uC7A5\uC18C \uC0C1\uC138 \uC815\uBCF4 (place_id\uB85C \uC870\uD68C)." },
|
|
1717
2274
|
args: {
|
|
1718
2275
|
placeId: { type: "positional", required: true, description: "Google place_id" },
|
|
@@ -1738,11 +2295,11 @@ var placeDetails = defineCommand8({
|
|
|
1738
2295
|
});
|
|
1739
2296
|
}
|
|
1740
2297
|
});
|
|
1741
|
-
var placeCommand =
|
|
2298
|
+
var placeCommand = defineCommand9({
|
|
1742
2299
|
meta: { name: "place", description: "\uC7A5\uC18C \uAC80\uC0C9/\uC0C1\uC138." },
|
|
1743
2300
|
subCommands: { search: placeSearch, "search-text": placeSearchText, details: placeDetails }
|
|
1744
2301
|
});
|
|
1745
|
-
var directionsCommand =
|
|
2302
|
+
var directionsCommand = defineCommand9({
|
|
1746
2303
|
meta: { name: "directions", description: "\uACBD\uB85C \uC548\uB0B4." },
|
|
1747
2304
|
args: {
|
|
1748
2305
|
from: { type: "string", required: true, description: "\uCD9C\uBC1C\uC9C0" },
|
|
@@ -1770,7 +2327,7 @@ var directionsCommand = defineCommand8({
|
|
|
1770
2327
|
});
|
|
1771
2328
|
}
|
|
1772
2329
|
});
|
|
1773
|
-
var weatherCommand =
|
|
2330
|
+
var weatherCommand = defineCommand9({
|
|
1774
2331
|
meta: { name: "weather", description: "\uB0A0\uC528 \uC870\uD68C." },
|
|
1775
2332
|
args: {
|
|
1776
2333
|
city: { type: "positional", required: true, description: "\uB3C4\uC2DC \uC774\uB984" },
|
|
@@ -1795,7 +2352,7 @@ var weatherCommand = defineCommand8({
|
|
|
1795
2352
|
});
|
|
1796
2353
|
}
|
|
1797
2354
|
});
|
|
1798
|
-
var flightStatusCommand =
|
|
2355
|
+
var flightStatusCommand = defineCommand9({
|
|
1799
2356
|
meta: { name: "flight-status", description: "\uD56D\uACF5\uD3B8 \uC0C1\uD0DC \uC870\uD68C." },
|
|
1800
2357
|
args: {
|
|
1801
2358
|
flightNumber: { type: "positional", required: true, description: "\uD56D\uACF5\uD3B8 \uBC88\uD638 (KE901)" },
|
|
@@ -1825,8 +2382,8 @@ var flightStatusCommand = defineCommand8({
|
|
|
1825
2382
|
// src/commands/feed.ts
|
|
1826
2383
|
init_command_helpers();
|
|
1827
2384
|
init_output();
|
|
1828
|
-
import { defineCommand as
|
|
1829
|
-
var list4 =
|
|
2385
|
+
import { defineCommand as defineCommand10 } from "citty";
|
|
2386
|
+
var list4 = defineCommand10({
|
|
1830
2387
|
meta: { name: "list", description: "\uD53C\uB4DC \uBAA9\uB85D." },
|
|
1831
2388
|
args: {
|
|
1832
2389
|
limit: { type: "string", description: "\uCD5C\uB300 \uD45C\uC2DC (\uAE30\uBCF8 20)" },
|
|
@@ -1854,7 +2411,7 @@ var list4 = defineCommand9({
|
|
|
1854
2411
|
});
|
|
1855
2412
|
}
|
|
1856
2413
|
});
|
|
1857
|
-
var post =
|
|
2414
|
+
var post = defineCommand10({
|
|
1858
2415
|
meta: { name: "post", description: "\uD53C\uB4DC \uAE00 \uC791\uC131." },
|
|
1859
2416
|
args: {
|
|
1860
2417
|
content: { type: "positional", required: true, description: "\uAE00 \uB0B4\uC6A9" },
|
|
@@ -1874,7 +2431,7 @@ var post = defineCommand9({
|
|
|
1874
2431
|
});
|
|
1875
2432
|
}
|
|
1876
2433
|
});
|
|
1877
|
-
var del3 =
|
|
2434
|
+
var del3 = defineCommand10({
|
|
1878
2435
|
meta: { name: "delete", description: "\uD53C\uB4DC \uAE00 \uC0AD\uC81C." },
|
|
1879
2436
|
args: {
|
|
1880
2437
|
id: { type: "positional", required: true, description: "\uD3EC\uC2A4\uD2B8 ID" },
|
|
@@ -1886,7 +2443,8 @@ var del3 = defineCommand9({
|
|
|
1886
2443
|
async run({ args }) {
|
|
1887
2444
|
await runFunctionCommand({
|
|
1888
2445
|
function: "delete_feed_post",
|
|
1889
|
-
|
|
2446
|
+
// 서버 router는 args.post_id를 읽음 (router.ts:284)
|
|
2447
|
+
args: { post_id: args.id },
|
|
1890
2448
|
outputFlag: args.output,
|
|
1891
2449
|
localeFlag: args.locale,
|
|
1892
2450
|
tripFlag: args.trip,
|
|
@@ -1895,7 +2453,7 @@ var del3 = defineCommand9({
|
|
|
1895
2453
|
});
|
|
1896
2454
|
}
|
|
1897
2455
|
});
|
|
1898
|
-
var feedCommand =
|
|
2456
|
+
var feedCommand = defineCommand10({
|
|
1899
2457
|
meta: { name: "feed", description: "\uD53C\uB4DC \uAD00\uB9AC." },
|
|
1900
2458
|
subCommands: { list: list4, post, delete: del3 }
|
|
1901
2459
|
});
|
|
@@ -1903,8 +2461,8 @@ var feedCommand = defineCommand9({
|
|
|
1903
2461
|
// src/commands/baby.ts
|
|
1904
2462
|
init_command_helpers();
|
|
1905
2463
|
init_output();
|
|
1906
|
-
import { defineCommand as
|
|
1907
|
-
var list5 =
|
|
2464
|
+
import { defineCommand as defineCommand11 } from "citty";
|
|
2465
|
+
var list5 = defineCommand11({
|
|
1908
2466
|
meta: { name: "list", description: "\uB4F1\uB85D\uB41C \uC544\uC774 \uBAA9\uB85D." },
|
|
1909
2467
|
args: {
|
|
1910
2468
|
locale: { type: "string", description: "ko|en|es|fr" },
|
|
@@ -1926,7 +2484,7 @@ var list5 = defineCommand10({
|
|
|
1926
2484
|
});
|
|
1927
2485
|
}
|
|
1928
2486
|
});
|
|
1929
|
-
var info =
|
|
2487
|
+
var info = defineCommand11({
|
|
1930
2488
|
meta: { name: "info", description: "\uC544\uC774 \uC815\uBCF4 \uC870\uD68C (\uC774\uB984 \uB610\uB294 \uBAA8\uB4E0 \uC544\uC774)." },
|
|
1931
2489
|
args: {
|
|
1932
2490
|
name: { type: "string", description: "\uC544\uC774 \uC774\uB984 (\uBBF8\uC9C0\uC815 \uC2DC \uBAA8\uB4E0 \uC544\uC774)" },
|
|
@@ -1937,7 +2495,8 @@ var info = defineCommand10({
|
|
|
1937
2495
|
async run({ args }) {
|
|
1938
2496
|
await runFunctionCommand({
|
|
1939
2497
|
function: "get_baby_info",
|
|
1940
|
-
|
|
2498
|
+
// 서버 router는 args.name_or_id ?? args.baby_name ?? args.name로 selector를 읽음
|
|
2499
|
+
args: { name_or_id: args.name, field: args.field ?? "all" },
|
|
1941
2500
|
outputFlag: args.output,
|
|
1942
2501
|
localeFlag: args.locale,
|
|
1943
2502
|
noTripContext: true,
|
|
@@ -1947,7 +2506,7 @@ var info = defineCommand10({
|
|
|
1947
2506
|
});
|
|
1948
2507
|
}
|
|
1949
2508
|
});
|
|
1950
|
-
var add4 =
|
|
2509
|
+
var add4 = defineCommand11({
|
|
1951
2510
|
meta: { name: "add", description: "\uC544\uC774 \uCD94\uAC00." },
|
|
1952
2511
|
args: {
|
|
1953
2512
|
name: { type: "string", required: true, description: "\uC774\uB984" },
|
|
@@ -1977,7 +2536,7 @@ var add4 = defineCommand10({
|
|
|
1977
2536
|
});
|
|
1978
2537
|
}
|
|
1979
2538
|
});
|
|
1980
|
-
var update3 =
|
|
2539
|
+
var update3 = defineCommand11({
|
|
1981
2540
|
meta: { name: "update", description: "\uC544\uC774 \uC815\uBCF4 \uC218\uC815." },
|
|
1982
2541
|
args: {
|
|
1983
2542
|
name: { type: "string", required: true, description: "\uC544\uC774 \uC774\uB984" },
|
|
@@ -1995,7 +2554,8 @@ var update3 = defineCommand10({
|
|
|
1995
2554
|
}
|
|
1996
2555
|
await runFunctionCommand({
|
|
1997
2556
|
function: "update_baby_info",
|
|
1998
|
-
args
|
|
2557
|
+
// 서버 router는 args.name_or_id ?? args.baby_name ?? args.name로 selector를 읽음
|
|
2558
|
+
args: { name_or_id: args.name, ...extraArgs },
|
|
1999
2559
|
outputFlag: args.output,
|
|
2000
2560
|
localeFlag: args.locale,
|
|
2001
2561
|
noTripContext: true,
|
|
@@ -2003,7 +2563,7 @@ var update3 = defineCommand10({
|
|
|
2003
2563
|
});
|
|
2004
2564
|
}
|
|
2005
2565
|
});
|
|
2006
|
-
var status =
|
|
2566
|
+
var status = defineCommand11({
|
|
2007
2567
|
meta: { name: "status", description: "\uC5EC\uD589 \uC911 \uC544\uC774 \uC0C1\uD0DC \uC5C5\uB370\uC774\uD2B8." },
|
|
2008
2568
|
args: {
|
|
2009
2569
|
name: { type: "string", required: true, description: "\uC544\uC774 \uC774\uB984" },
|
|
@@ -2015,7 +2575,8 @@ var status = defineCommand10({
|
|
|
2015
2575
|
async run({ args }) {
|
|
2016
2576
|
await runFunctionCommand({
|
|
2017
2577
|
function: "update_baby_status",
|
|
2018
|
-
|
|
2578
|
+
// 서버 router는 args.name_or_id ?? args.baby_name ?? args.name로 selector를 읽음
|
|
2579
|
+
args: { name_or_id: args.name, status: args.text },
|
|
2019
2580
|
outputFlag: args.output,
|
|
2020
2581
|
localeFlag: args.locale,
|
|
2021
2582
|
tripFlag: args.trip,
|
|
@@ -2023,7 +2584,7 @@ var status = defineCommand10({
|
|
|
2023
2584
|
});
|
|
2024
2585
|
}
|
|
2025
2586
|
});
|
|
2026
|
-
var note2 =
|
|
2587
|
+
var note2 = defineCommand11({
|
|
2027
2588
|
meta: { name: "note", description: "\uC5EC\uD589 \uBA54\uBAA8 \uCD94\uAC00." },
|
|
2028
2589
|
args: {
|
|
2029
2590
|
name: { type: "string", required: true, description: "\uC544\uC774 \uC774\uB984" },
|
|
@@ -2035,7 +2596,8 @@ var note2 = defineCommand10({
|
|
|
2035
2596
|
async run({ args }) {
|
|
2036
2597
|
await runFunctionCommand({
|
|
2037
2598
|
function: "add_baby_travel_note",
|
|
2038
|
-
|
|
2599
|
+
// 서버 router는 args.name_or_id ?? args.baby_name ?? args.name로 selector를 읽음
|
|
2600
|
+
args: { name_or_id: args.name, note: args.text },
|
|
2039
2601
|
outputFlag: args.output,
|
|
2040
2602
|
localeFlag: args.locale,
|
|
2041
2603
|
tripFlag: args.trip,
|
|
@@ -2043,7 +2605,7 @@ var note2 = defineCommand10({
|
|
|
2043
2605
|
});
|
|
2044
2606
|
}
|
|
2045
2607
|
});
|
|
2046
|
-
var del4 =
|
|
2608
|
+
var del4 = defineCommand11({
|
|
2047
2609
|
meta: { name: "delete", description: "\uC544\uC774 \uC815\uBCF4 \uC0AD\uC81C." },
|
|
2048
2610
|
args: {
|
|
2049
2611
|
name: { type: "positional", required: true, description: "\uC544\uC774 \uC774\uB984" },
|
|
@@ -2054,7 +2616,8 @@ var del4 = defineCommand10({
|
|
|
2054
2616
|
async run({ args }) {
|
|
2055
2617
|
await runFunctionCommand({
|
|
2056
2618
|
function: "delete_baby",
|
|
2057
|
-
|
|
2619
|
+
// 서버 router는 args.name_or_id를 읽음 (router.ts:338)
|
|
2620
|
+
args: { name_or_id: args.name },
|
|
2058
2621
|
outputFlag: args.output,
|
|
2059
2622
|
localeFlag: args.locale,
|
|
2060
2623
|
noTripContext: true,
|
|
@@ -2063,7 +2626,7 @@ var del4 = defineCommand10({
|
|
|
2063
2626
|
});
|
|
2064
2627
|
}
|
|
2065
2628
|
});
|
|
2066
|
-
var babyCommand =
|
|
2629
|
+
var babyCommand = defineCommand11({
|
|
2067
2630
|
meta: { name: "baby", description: "\uC544\uC774 \uC815\uBCF4 \uAD00\uB9AC." },
|
|
2068
2631
|
subCommands: { list: list5, info, add: add4, update: update3, status, note: note2, delete: del4 }
|
|
2069
2632
|
});
|
|
@@ -2071,8 +2634,8 @@ var babyCommand = defineCommand10({
|
|
|
2071
2634
|
// src/commands/social.ts
|
|
2072
2635
|
init_command_helpers();
|
|
2073
2636
|
init_output();
|
|
2074
|
-
import { defineCommand as
|
|
2075
|
-
var familyList =
|
|
2637
|
+
import { defineCommand as defineCommand12 } from "citty";
|
|
2638
|
+
var familyList = defineCommand12({
|
|
2076
2639
|
meta: { name: "list", description: "\uAC00\uC871 \uAD6C\uC131\uC6D0 \uBAA9\uB85D." },
|
|
2077
2640
|
args: {
|
|
2078
2641
|
locale: { type: "string", description: "ko|en|es|fr" },
|
|
@@ -2094,7 +2657,7 @@ var familyList = defineCommand11({
|
|
|
2094
2657
|
});
|
|
2095
2658
|
}
|
|
2096
2659
|
});
|
|
2097
|
-
var familyAddToTrip =
|
|
2660
|
+
var familyAddToTrip = defineCommand12({
|
|
2098
2661
|
meta: { name: "add-to-trip", description: "\uAC00\uC871 \uAD6C\uC131\uC6D0\uC744 \uD65C\uC131 trip\uC5D0 \uCD94\uAC00." },
|
|
2099
2662
|
args: {
|
|
2100
2663
|
names: { type: "string", description: "\uC27C\uD45C \uAD6C\uBD84 \uC774\uB984 \uBAA9\uB85D (\uBBF8\uC9C0\uC815 \uC2DC \uBAA8\uB4E0 \uAC00\uC871)" },
|
|
@@ -2105,7 +2668,8 @@ var familyAddToTrip = defineCommand11({
|
|
|
2105
2668
|
async run({ args }) {
|
|
2106
2669
|
await runFunctionCommand({
|
|
2107
2670
|
function: "add_family_to_trip",
|
|
2108
|
-
|
|
2671
|
+
// 서버 router는 args.member_names를 읽음 (router.ts:430)
|
|
2672
|
+
args: { member_names: args.names },
|
|
2109
2673
|
outputFlag: args.output,
|
|
2110
2674
|
localeFlag: args.locale,
|
|
2111
2675
|
tripFlag: args.trip,
|
|
@@ -2113,11 +2677,11 @@ var familyAddToTrip = defineCommand11({
|
|
|
2113
2677
|
});
|
|
2114
2678
|
}
|
|
2115
2679
|
});
|
|
2116
|
-
var familyCommand =
|
|
2680
|
+
var familyCommand = defineCommand12({
|
|
2117
2681
|
meta: { name: "family", description: "\uAC00\uC871 \uAD00\uB9AC." },
|
|
2118
2682
|
subCommands: { list: familyList, "add-to-trip": familyAddToTrip }
|
|
2119
2683
|
});
|
|
2120
|
-
var friendList =
|
|
2684
|
+
var friendList = defineCommand12({
|
|
2121
2685
|
meta: { name: "list", description: "\uCE5C\uAD6C \uBAA9\uB85D." },
|
|
2122
2686
|
args: {
|
|
2123
2687
|
locale: { type: "string", description: "ko|en|es|fr" },
|
|
@@ -2139,7 +2703,7 @@ var friendList = defineCommand11({
|
|
|
2139
2703
|
});
|
|
2140
2704
|
}
|
|
2141
2705
|
});
|
|
2142
|
-
var friendAdd =
|
|
2706
|
+
var friendAdd = defineCommand12({
|
|
2143
2707
|
meta: { name: "add", description: "\uCE5C\uAD6C \uCD94\uAC00 (\uC774\uBA54\uC77C)." },
|
|
2144
2708
|
args: {
|
|
2145
2709
|
email: { type: "positional", required: true, description: "\uC774\uBA54\uC77C \uC8FC\uC18C" },
|
|
@@ -2157,11 +2721,11 @@ var friendAdd = defineCommand11({
|
|
|
2157
2721
|
});
|
|
2158
2722
|
}
|
|
2159
2723
|
});
|
|
2160
|
-
var friendCommand =
|
|
2724
|
+
var friendCommand = defineCommand12({
|
|
2161
2725
|
meta: { name: "friend", description: "\uCE5C\uAD6C \uAD00\uB9AC." },
|
|
2162
2726
|
subCommands: { list: friendList, add: friendAdd }
|
|
2163
2727
|
});
|
|
2164
|
-
var inviteList =
|
|
2728
|
+
var inviteList = defineCommand12({
|
|
2165
2729
|
meta: { name: "list", description: "\uD65C\uC131 trip\uC758 \uCD08\uB300 \uBAA9\uB85D." },
|
|
2166
2730
|
args: {
|
|
2167
2731
|
trip: { type: "string", description: "Trip UUID" },
|
|
@@ -2184,7 +2748,7 @@ var inviteList = defineCommand11({
|
|
|
2184
2748
|
});
|
|
2185
2749
|
}
|
|
2186
2750
|
});
|
|
2187
|
-
var inviteCreate =
|
|
2751
|
+
var inviteCreate = defineCommand12({
|
|
2188
2752
|
meta: { name: "create", description: "trip \uCD08\uB300 \uC0DD\uC131." },
|
|
2189
2753
|
args: {
|
|
2190
2754
|
email: { type: "string", description: "\uCD08\uB300\uD560 \uC774\uBA54\uC77C (\uC0DD\uB7B5 \uC2DC \uACF5\uAC1C \uCF54\uB4DC \uBC1C\uAE09)" },
|
|
@@ -2210,15 +2774,15 @@ var inviteCreate = defineCommand11({
|
|
|
2210
2774
|
});
|
|
2211
2775
|
}
|
|
2212
2776
|
});
|
|
2213
|
-
var inviteCommand =
|
|
2777
|
+
var inviteCommand = defineCommand12({
|
|
2214
2778
|
meta: { name: "invite", description: "\uCD08\uB300 \uAD00\uB9AC." },
|
|
2215
2779
|
subCommands: { list: inviteList, create: inviteCreate }
|
|
2216
2780
|
});
|
|
2217
2781
|
|
|
2218
2782
|
// src/commands/web.ts
|
|
2219
2783
|
init_command_helpers();
|
|
2220
|
-
import { defineCommand as
|
|
2221
|
-
var webCommand =
|
|
2784
|
+
import { defineCommand as defineCommand13 } from "citty";
|
|
2785
|
+
var webCommand = defineCommand13({
|
|
2222
2786
|
meta: { name: "web", description: "\uC6F9 \uAC80\uC0C9 (Perplexity)." },
|
|
2223
2787
|
args: {
|
|
2224
2788
|
query: { type: "positional", required: true, description: "\uAC80\uC0C9\uC5B4" },
|
|
@@ -2251,8 +2815,8 @@ var webCommand = defineCommand12({
|
|
|
2251
2815
|
|
|
2252
2816
|
// src/commands/raw.ts
|
|
2253
2817
|
init_command_helpers();
|
|
2254
|
-
import { defineCommand as
|
|
2255
|
-
var rawCommand =
|
|
2818
|
+
import { defineCommand as defineCommand14 } from "citty";
|
|
2819
|
+
var rawCommand = defineCommand14({
|
|
2256
2820
|
meta: {
|
|
2257
2821
|
name: "raw",
|
|
2258
2822
|
description: "\uD568\uC218\uB97C \uC774\uB984\uC73C\uB85C \uC9C1\uC811 \uD638\uCD9C (escape hatch)."
|
|
@@ -2297,8 +2861,8 @@ init_config();
|
|
|
2297
2861
|
init_output();
|
|
2298
2862
|
init_exit_codes();
|
|
2299
2863
|
init_prompt();
|
|
2300
|
-
import { defineCommand as
|
|
2301
|
-
async function*
|
|
2864
|
+
import { defineCommand as defineCommand15 } from "citty";
|
|
2865
|
+
async function* parseSseStream2(response) {
|
|
2302
2866
|
if (!response.body) return;
|
|
2303
2867
|
const reader = response.body.getReader();
|
|
2304
2868
|
const decoder = new TextDecoder();
|
|
@@ -2357,7 +2921,7 @@ async function streamChatTurn(history, options) {
|
|
|
2357
2921
|
let reply = "";
|
|
2358
2922
|
const toolCalls = [];
|
|
2359
2923
|
const c = colorize({ mode: options.mode, color: options.color });
|
|
2360
|
-
for await (const ev of
|
|
2924
|
+
for await (const ev of parseSseStream2(response)) {
|
|
2361
2925
|
if (ev.event === "text") {
|
|
2362
2926
|
const chunk = String(ev.data.text ?? "");
|
|
2363
2927
|
reply += chunk;
|
|
@@ -2376,7 +2940,7 @@ async function streamChatTurn(history, options) {
|
|
|
2376
2940
|
if (options.mode === "pretty") process.stdout.write("\n");
|
|
2377
2941
|
return { reply, toolCalls };
|
|
2378
2942
|
}
|
|
2379
|
-
var chatCommand =
|
|
2943
|
+
var chatCommand = defineCommand15({
|
|
2380
2944
|
meta: { name: "chat", description: "AI \uCC57 (\uC790\uC5F0\uC5B4 \u2192 \uD568\uC218 \uD638\uCD9C). \uC778\uC790 \uC788\uC73C\uBA74 single-shot." },
|
|
2381
2945
|
args: {
|
|
2382
2946
|
prompt: { type: "positional", required: false, description: "\uC9C8\uBB38 (\uC0DD\uB7B5 \uC2DC \uBA40\uD2F0\uD134 REPL)" },
|
|
@@ -2427,7 +2991,7 @@ var chatCommand = defineCommand14({
|
|
|
2427
2991
|
});
|
|
2428
2992
|
|
|
2429
2993
|
// src/commands/completion.ts
|
|
2430
|
-
import { defineCommand as
|
|
2994
|
+
import { defineCommand as defineCommand16 } from "citty";
|
|
2431
2995
|
var COMMAND_TREE = {
|
|
2432
2996
|
auth: ["login", "logout", "whoami", "tokens"],
|
|
2433
2997
|
config: ["get", "set", "path"],
|
|
@@ -2525,7 +3089,7 @@ function fishCompletion() {
|
|
|
2525
3089
|
}
|
|
2526
3090
|
return lines.join("\n") + "\n";
|
|
2527
3091
|
}
|
|
2528
|
-
var completionCommand =
|
|
3092
|
+
var completionCommand = defineCommand16({
|
|
2529
3093
|
meta: { name: "completion", description: "\uC178 \uC790\uB3D9\uC644\uC131 \uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 (bash|zsh|fish)." },
|
|
2530
3094
|
args: {
|
|
2531
3095
|
shell: { type: "positional", required: true, description: "bash | zsh | fish" }
|
|
@@ -2552,7 +3116,7 @@ var completionCommand = defineCommand15({
|
|
|
2552
3116
|
});
|
|
2553
3117
|
|
|
2554
3118
|
// src/index.ts
|
|
2555
|
-
var main =
|
|
3119
|
+
var main = defineCommand17({
|
|
2556
3120
|
meta: {
|
|
2557
3121
|
name: "dodo",
|
|
2558
3122
|
version: "0.1.0",
|
|
@@ -2564,6 +3128,7 @@ var main = defineCommand16({
|
|
|
2564
3128
|
config: configCommand,
|
|
2565
3129
|
// 핵심 데이터
|
|
2566
3130
|
trip: tripCommand,
|
|
3131
|
+
profile: profileCommand,
|
|
2567
3132
|
expense: expenseCommand,
|
|
2568
3133
|
booking: bookingCommand,
|
|
2569
3134
|
itinerary: itineraryCommand,
|