@duyquangnvx/create-agent-cli 0.32.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/bin.js +113 -58
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,21 @@ What changed in each release of `@duyquangnvx/agent-cli` (the Runtime) and `@duy
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## v0.33.0 (2026-11-10)
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Breaking:** `ctx.login(name)` returns `Promise<string>`, and the Runtime finds a Login when the Command first asks for it, once per run, no longer before `plan`, `run` or `start`: write `await ctx.login(name)`. A Command that lists a Login and returns before it asks runs on a machine not signed in, and one that asks with none stored fails with `APPROVAL_PENDING` from that call, or with `LOGIN_REQUIRED` in a dry run, which names that Login alone; of Logins asked for at once, only the first one missing starts an Approval. Ask before any effect a rerun must not repeat.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- A Login's device or token endpoint that answers with a body that is not JSON, or with JSON that is no OAuth answer, such as a proxy or a password page in front of the server, fails the run with the new Runtime code `NOT_OAUTH` (exit 3), naming the endpoint and its status in the message and in `details` (`login`, `endpoint`, `status`), where it failed with `INTERNAL` (exit 70). `runtimeCodes.NOT_OAUTH` is exported.
|
|
16
|
+
|
|
17
|
+
### Upgrade from v0.32.0
|
|
18
|
+
|
|
19
|
+
- Every call of `ctx.login(name)` becomes `await ctx.login(name)`: a call left without it still type-checks inside a template literal, and sends `[object Promise]` as the token.
|
|
20
|
+
- A Command with an effect before its first `ctx.login` asks first, since the rerun after an Approval starts the Command over.
|
|
21
|
+
|
|
7
22
|
## v0.32.0 (2026-11-10)
|
|
8
23
|
|
|
9
24
|
### Added
|
package/dist/bin.js
CHANGED
|
@@ -7815,6 +7815,7 @@ const APPROVAL_PENDING = "APPROVAL_PENDING";
|
|
|
7815
7815
|
const APPROVAL_DENIED = "APPROVAL_DENIED";
|
|
7816
7816
|
const APPROVAL_EXPIRED = "APPROVAL_EXPIRED";
|
|
7817
7817
|
const LOGIN_REJECTED = "LOGIN_REJECTED";
|
|
7818
|
+
const NOT_OAUTH = "NOT_OAUTH";
|
|
7818
7819
|
function loginStep(name) {
|
|
7819
7820
|
return ["login", name];
|
|
7820
7821
|
}
|
|
@@ -7831,6 +7832,7 @@ function loginRequired(names, rerun) {
|
|
|
7831
7832
|
}
|
|
7832
7833
|
function loginAsking(name) {
|
|
7833
7834
|
return {
|
|
7835
|
+
login: name,
|
|
7834
7836
|
subject: `signing in to ${name}`,
|
|
7835
7837
|
denied: () => approvalDenied(name),
|
|
7836
7838
|
expired: () => approvalExpired(name)
|
|
@@ -7840,6 +7842,7 @@ function loginAsking(name) {
|
|
|
7840
7842
|
function grantAsking(name, scope, rerun) {
|
|
7841
7843
|
const subject = `the grant of ${scope} from ${name}`;
|
|
7842
7844
|
return {
|
|
7845
|
+
login: name,
|
|
7843
7846
|
subject,
|
|
7844
7847
|
denied: () => new CliError({
|
|
7845
7848
|
code: APPROVAL_DENIED,
|
|
@@ -7897,6 +7900,19 @@ function approvalExpired(name) {
|
|
|
7897
7900
|
next: [loginStep(name)]
|
|
7898
7901
|
});
|
|
7899
7902
|
}
|
|
7903
|
+
/** An endpoint of a Login that answered as something other than its OAuth server. */
|
|
7904
|
+
function notOAuth({ login, url: endpoint }, status, cause) {
|
|
7905
|
+
return new CliError({
|
|
7906
|
+
code: NOT_OAUTH,
|
|
7907
|
+
message: `${endpoint} answered ${status}, which is no OAuth answer`,
|
|
7908
|
+
hint: `${endpoint} does not reach the OAuth server the Login ${login} declares: a proxy or a password page may stand in front of it, or the CLI points at the wrong server; ask whoever runs ${new URL(endpoint).origin} for the URL that reaches it`,
|
|
7909
|
+
details: {
|
|
7910
|
+
login,
|
|
7911
|
+
endpoint,
|
|
7912
|
+
status
|
|
7913
|
+
}
|
|
7914
|
+
}, { cause });
|
|
7915
|
+
}
|
|
7900
7916
|
//#endregion
|
|
7901
7917
|
//#region ../agent-cli/dist/runtime-codes.js
|
|
7902
7918
|
const DOCTOR_PROBLEMS = "DOCTOR_PROBLEMS";
|
|
@@ -7940,7 +7956,8 @@ const anyCommandErrors = {
|
|
|
7940
7956
|
[APPROVAL_PENDING]: { class: "wait" },
|
|
7941
7957
|
[APPROVAL_DENIED]: { class: "operator" },
|
|
7942
7958
|
[APPROVAL_EXPIRED]: { class: "operator" },
|
|
7943
|
-
[LOGIN_REJECTED]: { class: "operator" }
|
|
7959
|
+
[LOGIN_REJECTED]: { class: "operator" },
|
|
7960
|
+
[NOT_OAUTH]: { class: "source" }
|
|
7944
7961
|
};
|
|
7945
7962
|
/**
|
|
7946
7963
|
* The Runtime codes only some Commands reach: each Command that throws one, Built-in or the CLI's
|
|
@@ -8087,9 +8104,12 @@ const errorSchema = object({ error: string() });
|
|
|
8087
8104
|
function isoAfter(clock, seconds) {
|
|
8088
8105
|
return new Date(clock.now() + seconds * MS_PER_S).toISOString();
|
|
8089
8106
|
}
|
|
8090
|
-
/**
|
|
8091
|
-
|
|
8092
|
-
|
|
8107
|
+
/**
|
|
8108
|
+
* POSTs `form` to an OAuth endpoint and parses its JSON answer, whatever its status. A body that
|
|
8109
|
+
* is not JSON fails with `NOT_OAUTH`.
|
|
8110
|
+
*/
|
|
8111
|
+
async function postForm(fetch, endpoint, form, { ignoreStop } = {}) {
|
|
8112
|
+
const response = await fetch(endpoint.url, {
|
|
8093
8113
|
method: "POST",
|
|
8094
8114
|
once: false,
|
|
8095
8115
|
...ignoreStop === void 0 ? {} : { ignoreStop },
|
|
@@ -8097,15 +8117,21 @@ async function postForm(fetch, url, form, { ignoreStop } = {}) {
|
|
|
8097
8117
|
body: new URLSearchParams(form)
|
|
8098
8118
|
});
|
|
8099
8119
|
const text = await response.text();
|
|
8120
|
+
const { status } = response;
|
|
8100
8121
|
try {
|
|
8101
|
-
return
|
|
8122
|
+
return {
|
|
8123
|
+
endpoint,
|
|
8124
|
+
status,
|
|
8125
|
+
body: JSON.parse(text)
|
|
8126
|
+
};
|
|
8102
8127
|
} catch (error) {
|
|
8103
|
-
throw
|
|
8128
|
+
throw notOAuth(endpoint, status, error);
|
|
8104
8129
|
}
|
|
8105
8130
|
}
|
|
8106
|
-
|
|
8131
|
+
/** The answer's body as `schema` has it, or a `NOT_OAUTH` for one of another shape. */
|
|
8132
|
+
function parsedAnswer(schema, { endpoint, status, body }) {
|
|
8107
8133
|
const parsed = schema.safeParse(body);
|
|
8108
|
-
if (!parsed.success) throw
|
|
8134
|
+
if (!parsed.success) throw notOAuth(endpoint, status);
|
|
8109
8135
|
return parsed.data;
|
|
8110
8136
|
}
|
|
8111
8137
|
function storedLoginOf({ access_token, refresh_token, expires_in }, clock) {
|
|
@@ -8131,8 +8157,12 @@ async function refreshed(name, login, file, refreshToken, ctx) {
|
|
|
8131
8157
|
client_id: login.clientId
|
|
8132
8158
|
};
|
|
8133
8159
|
return await ctx.runToEnd(`refreshing the Login ${name}`, async () => {
|
|
8134
|
-
const
|
|
8135
|
-
|
|
8160
|
+
const endpoint = {
|
|
8161
|
+
login: name,
|
|
8162
|
+
url: login.tokenEndpoint
|
|
8163
|
+
};
|
|
8164
|
+
const answer = await postForm(ctx.fetch, endpoint, form, { ignoreStop: true });
|
|
8165
|
+
const granted = tokenSchema.safeParse(answer.body);
|
|
8136
8166
|
if (granted.success) {
|
|
8137
8167
|
const stored = {
|
|
8138
8168
|
refreshToken,
|
|
@@ -8141,7 +8171,7 @@ async function refreshed(name, login, file, refreshToken, ctx) {
|
|
|
8141
8171
|
await file.write(stored);
|
|
8142
8172
|
return stored;
|
|
8143
8173
|
}
|
|
8144
|
-
const { error } = parsedAnswer(errorSchema,
|
|
8174
|
+
const { error } = parsedAnswer(errorSchema, answer);
|
|
8145
8175
|
if (error !== "invalid_grant") throw new Error(`${login.tokenEndpoint} refused the refresh of ${name} with ${error}`);
|
|
8146
8176
|
await file.remove();
|
|
8147
8177
|
});
|
|
@@ -8242,9 +8272,9 @@ function loginRows(logins, runAs) {
|
|
|
8242
8272
|
/** The bundler's stamp, absent when the CLI runs unbundled. Read per call, so a test can define it. */
|
|
8243
8273
|
function buildStamp() {
|
|
8244
8274
|
return {
|
|
8245
|
-
"sha": "
|
|
8275
|
+
"sha": "3716c19",
|
|
8246
8276
|
"dirty": false,
|
|
8247
|
-
"builtAt": "2026-11-
|
|
8277
|
+
"builtAt": "2026-11-10T16:12:55.000Z"
|
|
8248
8278
|
};
|
|
8249
8279
|
}
|
|
8250
8280
|
/** The first line of `--version`: the version, and the commit and time of a stamped build. */
|
|
@@ -10102,12 +10132,18 @@ const deviceSchema = object({
|
|
|
10102
10132
|
expires_in: number$1(),
|
|
10103
10133
|
interval: number$1().optional()
|
|
10104
10134
|
});
|
|
10105
|
-
async function startApproval(login, { fetch, clock }) {
|
|
10135
|
+
async function startApproval(name, login, { fetch, clock }) {
|
|
10106
10136
|
const form = {
|
|
10107
10137
|
client_id: login.clientId,
|
|
10108
10138
|
...login.scope === void 0 ? {} : { scope: login.scope }
|
|
10109
10139
|
};
|
|
10110
|
-
const
|
|
10140
|
+
const answer = await postForm(fetch, {
|
|
10141
|
+
login: name,
|
|
10142
|
+
url: login.deviceEndpoint
|
|
10143
|
+
}, form);
|
|
10144
|
+
const refused = errorSchema.safeParse(answer.body);
|
|
10145
|
+
if (refused.success) throw new Error(`${login.deviceEndpoint} refused the device request with ${refused.data.error}`);
|
|
10146
|
+
const device = parsedAnswer(deviceSchema, answer);
|
|
10111
10147
|
return {
|
|
10112
10148
|
deviceCode: device.device_code,
|
|
10113
10149
|
userCode: device.user_code,
|
|
@@ -10123,13 +10159,17 @@ async function pollApproval(asking, login, { approval, takenUp }, scope, signal)
|
|
|
10123
10159
|
device_code: approval.deviceCode,
|
|
10124
10160
|
client_id: login.clientId
|
|
10125
10161
|
};
|
|
10162
|
+
const endpoint = {
|
|
10163
|
+
login: asking.login,
|
|
10164
|
+
url: login.tokenEndpoint
|
|
10165
|
+
};
|
|
10126
10166
|
let intervalS = approval.interval;
|
|
10127
10167
|
for (let first = true;; first = false) {
|
|
10128
10168
|
if (!(first && takenUp)) await scope.clock.sleep(intervalS * MS_PER_S, signal);
|
|
10129
|
-
const
|
|
10130
|
-
const granted = tokenSchema.safeParse(body);
|
|
10169
|
+
const answer = await postForm(scope.fetch, endpoint, form);
|
|
10170
|
+
const granted = tokenSchema.safeParse(answer.body);
|
|
10131
10171
|
if (granted.success) return storedLoginOf(granted.data, scope.clock);
|
|
10132
|
-
const { error } = parsedAnswer(errorSchema,
|
|
10172
|
+
const { error } = parsedAnswer(errorSchema, answer);
|
|
10133
10173
|
if (error === "slow_down") intervalS += SLOW_DOWN_S;
|
|
10134
10174
|
else if (error !== "authorization_pending") throw refusal(asking, login, error);
|
|
10135
10175
|
}
|
|
@@ -10144,9 +10184,9 @@ function endsApproval(error) {
|
|
|
10144
10184
|
return error instanceof CliError && (error.code === "APPROVAL_DENIED" || error.code === "APPROVAL_EXPIRED");
|
|
10145
10185
|
}
|
|
10146
10186
|
/** Takes up the pending Approval, or asks for one and keeps it as a User file, and prints its code. */
|
|
10147
|
-
async function askedApproval(login, file, scope) {
|
|
10187
|
+
async function askedApproval(name, login, file, scope) {
|
|
10148
10188
|
const pending = await readUnexpired(file, scope.clock);
|
|
10149
|
-
const approval = pending ?? await startApproval(login, scope);
|
|
10189
|
+
const approval = pending ?? await startApproval(name, login, scope);
|
|
10150
10190
|
if (pending === void 0) await file.write(approval);
|
|
10151
10191
|
scope.progress(`open ${approval.verificationUriComplete ?? approval.verificationUri} and approve code ${approval.userCode}`);
|
|
10152
10192
|
return {
|
|
@@ -10156,7 +10196,7 @@ async function askedApproval(login, file, scope) {
|
|
|
10156
10196
|
}
|
|
10157
10197
|
/** The `APPROVAL_PENDING` of the pending Approval, or of a new one, without polling it. */
|
|
10158
10198
|
async function pendingApproval(name, login, files, scope, rerun) {
|
|
10159
|
-
const { approval } = await askedApproval(login, files.approval, scope);
|
|
10199
|
+
const { approval } = await askedApproval(name, login, files.approval, scope);
|
|
10160
10200
|
return approvalPending(loginAsking(name), approval, rerun);
|
|
10161
10201
|
}
|
|
10162
10202
|
/**
|
|
@@ -10164,7 +10204,7 @@ async function pendingApproval(name, login, files, scope, rerun) {
|
|
|
10164
10204
|
* refused or expired. An approved one stays until what it granted is kept, so a cut-off run loses nothing.
|
|
10165
10205
|
*/
|
|
10166
10206
|
async function approved(asking, login, file, scope, { waitS, rerun }) {
|
|
10167
|
-
const asked = await askedApproval(login, file, scope);
|
|
10207
|
+
const asked = await askedApproval(asking.login, login, file, scope);
|
|
10168
10208
|
const wait = scope.deadline(waitS * MS_PER_S);
|
|
10169
10209
|
let granted;
|
|
10170
10210
|
try {
|
|
@@ -12221,48 +12261,60 @@ function approvalRerun(ctx) {
|
|
|
12221
12261
|
add: [WAIT_FLAG.flag, String(100)]
|
|
12222
12262
|
});
|
|
12223
12263
|
}
|
|
12224
|
-
|
|
12225
|
-
|
|
12226
|
-
|
|
12227
|
-
|
|
12228
|
-
|
|
12229
|
-
|
|
12230
|
-
|
|
12264
|
+
/** The token of the Login `name`, signing in first, for at most `waitS` seconds, when none is found. */
|
|
12265
|
+
async function tokenOf(name, logins, ctx, waitS) {
|
|
12266
|
+
const login = declaredLogin(logins, name, ctx.env);
|
|
12267
|
+
const found = ctx.dryRun ? await currentTokenOf(login, tokenScopeOf(ctx)) : await freshTokenOf(name, login, ctx);
|
|
12268
|
+
if (found === void 0 && ctx.dryRun) throw loginRequired([name], ctx.rerun());
|
|
12269
|
+
const token = found ?? storedToken(await signIn(name, login, loginFilesOf(ctx.userFile, login), ctx, {
|
|
12270
|
+
waitS,
|
|
12271
|
+
rerun: approvalRerun(ctx)
|
|
12231
12272
|
}));
|
|
12232
|
-
const missing = found.flatMap(({ name, token }) => token === void 0 ? [name] : []);
|
|
12233
|
-
if (missing.length > 0 && ctx.dryRun) throw loginRequired(missing, ctx.rerun());
|
|
12234
|
-
const tokens = /* @__PURE__ */ new Map();
|
|
12235
|
-
for (const { name, token } of found) {
|
|
12236
|
-
if (token !== void 0) {
|
|
12237
|
-
tokens.set(name, token);
|
|
12238
|
-
continue;
|
|
12239
|
-
}
|
|
12240
|
-
const login = declaredLogin(logins, name, ctx.env);
|
|
12241
|
-
const stored = await signIn(name, login, loginFilesOf(ctx.userFile, login), ctx, {
|
|
12242
|
-
waitS,
|
|
12243
|
-
rerun: approvalRerun(ctx)
|
|
12244
|
-
});
|
|
12245
|
-
tokens.set(name, storedToken(stored));
|
|
12246
|
-
}
|
|
12247
12273
|
ctx.signal.throwIfAborted();
|
|
12248
|
-
return
|
|
12274
|
+
return token;
|
|
12275
|
+
}
|
|
12276
|
+
/**
|
|
12277
|
+
* `ctx.login`, which finds each Login once, when first asked, and the tokens it gave. A Login it
|
|
12278
|
+
* fails to find fails every Login asked for after it the same way.
|
|
12279
|
+
*/
|
|
12280
|
+
function loggingIn(ctx, names, logins, waitS) {
|
|
12281
|
+
const asked = /* @__PURE__ */ new Map();
|
|
12282
|
+
const given = /* @__PURE__ */ new Map();
|
|
12283
|
+
let turn = Promise.resolve();
|
|
12284
|
+
const find = async (name, earlier) => {
|
|
12285
|
+
await earlier;
|
|
12286
|
+
const token = await tokenOf(name, logins, ctx, waitS);
|
|
12287
|
+
given.set(name, token);
|
|
12288
|
+
return token;
|
|
12289
|
+
};
|
|
12290
|
+
const login = async (name) => {
|
|
12291
|
+
if (!names.includes(name)) undeclaredLogin(name);
|
|
12292
|
+
const asking = asked.get(name) ?? find(name, turn);
|
|
12293
|
+
asked.set(name, asking);
|
|
12294
|
+
turn = asking;
|
|
12295
|
+
return (await asking).value;
|
|
12296
|
+
};
|
|
12297
|
+
return {
|
|
12298
|
+
login,
|
|
12299
|
+
given
|
|
12300
|
+
};
|
|
12249
12301
|
}
|
|
12250
12302
|
/** The Login a `LOGIN_REJECTED` names in `details.login`, or the Command's only one. */
|
|
12251
|
-
function rejectedName(rejected,
|
|
12303
|
+
function rejectedName(rejected, names) {
|
|
12252
12304
|
const { details } = rejected;
|
|
12253
12305
|
if (typeof details === "object" && details !== null && "login" in details) return typeof details.login === "string" ? details.login : void 0;
|
|
12254
|
-
const [only, ...rest] =
|
|
12306
|
+
const [only, ...rest] = names;
|
|
12255
12307
|
return rest.length === 0 ? only : void 0;
|
|
12256
12308
|
}
|
|
12257
12309
|
/**
|
|
12258
12310
|
* What a run whose Command threw `error` fails with: a `LOGIN_REJECTED` of a stored Login drops
|
|
12259
12311
|
* it for a new Approval, one of a Secret's token fails as the operator's to fix.
|
|
12260
12312
|
*/
|
|
12261
|
-
async function afterRejection(error,
|
|
12313
|
+
async function afterRejection(error, { names, given }, logins, ctx) {
|
|
12262
12314
|
if (!(error instanceof CliError && error.code === "LOGIN_REJECTED")) return error;
|
|
12263
|
-
const name = rejectedName(error,
|
|
12264
|
-
const token = name === void 0 ? void 0 :
|
|
12265
|
-
if (name === void 0 || token === void 0) return new Error(`the Command threw ${LOGIN_REJECTED} naming no Login it
|
|
12315
|
+
const name = rejectedName(error, names);
|
|
12316
|
+
const token = name === void 0 ? void 0 : given.get(name);
|
|
12317
|
+
if (name === void 0 || token === void 0) return new Error(`the Command threw ${LOGIN_REJECTED} naming no Login ctx.login gave it in details.login`, { cause: error });
|
|
12266
12318
|
const login = declaredLogin(logins, name, ctx.env);
|
|
12267
12319
|
if (token.source.kind === "secret" && login.secret !== void 0) return secretRejected(name, login.secret, error);
|
|
12268
12320
|
const files = loginFilesOf(ctx.userFile, login);
|
|
@@ -12286,20 +12338,23 @@ function granting(ctx, grants, logins, waitS) {
|
|
|
12286
12338
|
};
|
|
12287
12339
|
}
|
|
12288
12340
|
/**
|
|
12289
|
-
* Runs `work` with a `ctx` whose `login`
|
|
12290
|
-
* most `waitS` seconds, where
|
|
12341
|
+
* Runs `work` with a `ctx` whose `login` finds a named Login's token when first asked, signing in
|
|
12342
|
+
* first, for at most `waitS` seconds, where it is missing, and whose `grant` asks for a Grant. A
|
|
12291
12343
|
* `LOGIN_REJECTED` from `work` drops the stored Login.
|
|
12292
12344
|
*/
|
|
12293
12345
|
async function withLogins(ctx, { logins: names, grants }, logins, waitS, work) {
|
|
12294
|
-
const
|
|
12346
|
+
const { login, given } = loggingIn(ctx, names, logins, waitS ?? 0);
|
|
12295
12347
|
const loggedIn = derived(ctx, {
|
|
12296
|
-
login
|
|
12348
|
+
login,
|
|
12297
12349
|
grant: granting(ctx, grants, logins, waitS ?? 0)
|
|
12298
12350
|
});
|
|
12299
12351
|
try {
|
|
12300
12352
|
return await work(loggedIn);
|
|
12301
12353
|
} catch (error) {
|
|
12302
|
-
throw await afterRejection(error,
|
|
12354
|
+
throw await afterRejection(error, {
|
|
12355
|
+
names,
|
|
12356
|
+
given
|
|
12357
|
+
}, logins, ctx);
|
|
12303
12358
|
}
|
|
12304
12359
|
}
|
|
12305
12360
|
/** `ctx.grant` of a name the Command does not declare in `grants`, which only a cast reaches. */
|
|
@@ -12607,7 +12662,7 @@ function contextOf(scope, control, { command, flags, project, deliver, latestRel
|
|
|
12607
12662
|
return {
|
|
12608
12663
|
...portsBase,
|
|
12609
12664
|
secret,
|
|
12610
|
-
login: undeclaredLogin,
|
|
12665
|
+
login: async (name) => undeclaredLogin(name),
|
|
12611
12666
|
grant: async (name) => undeclaredGrant(name),
|
|
12612
12667
|
userFile: scope.userFile,
|
|
12613
12668
|
fail: cliErrorOf,
|
|
@@ -12967,7 +13022,7 @@ async function runProcess(cli) {
|
|
|
12967
13022
|
//#region package.json
|
|
12968
13023
|
var package_default = {
|
|
12969
13024
|
name: "@duyquangnvx/create-agent-cli",
|
|
12970
|
-
version: "0.
|
|
13025
|
+
version: "0.33.0",
|
|
12971
13026
|
description: "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
12972
13027
|
type: "module",
|
|
12973
13028
|
engines: { "node": ">=22.12.0" },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@duyquangnvx/create-agent-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Creates a new Agent CLI repository wired to @duyquangnvx/agent-cli.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"access": "public"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@duyquangnvx/agent-cli": "0.
|
|
24
|
+
"@duyquangnvx/agent-cli": "0.33.0",
|
|
25
25
|
"tsdown": "0.23.0",
|
|
26
26
|
"zod": "4.6.7"
|
|
27
27
|
},
|