akm-cli 0.9.15 → 0.9.16-alpha.2
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 +52 -0
- package/dist/assets/hints/cli-hints-full.md +13 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +3 -6
- package/dist/cli/retired-commands.js +0 -2
- package/dist/commands/env/env-binding.js +4 -4
- package/dist/commands/env/env-cli.js +3 -3
- package/dist/commands/improve/improve-cli.js +19 -14
- package/dist/commands/improve/reflect.js +23 -2
- package/dist/commands/lint/base-linter.js +9 -0
- package/dist/commands/lint/env-key-rules.js +2 -2
- package/dist/commands/proposal/propose.js +15 -1
- package/dist/commands/proposal/validators/proposal-quality-validators.js +40 -3
- package/dist/commands/proposal/validators/proposal-validators.js +5 -4
- package/dist/commands/read/search.js +33 -4
- package/dist/commands/read/show.js +21 -2
- package/dist/commands/registry-cli.js +5 -5
- package/dist/commands/sources/add-cli.js +59 -16
- package/dist/commands/sources/bundle-cli.js +35 -11
- package/dist/commands/sources/bundle-config-ops.js +30 -0
- package/dist/commands/sources/dangerous-env-audit.js +4 -4
- package/dist/commands/sources/installed-stashes.js +43 -28
- package/dist/commands/sources/source-add.js +33 -17
- package/dist/commands/sources/source-manage.js +34 -12
- package/dist/commands/sources/stash-skeleton.js +6 -3
- package/dist/commands/tasks/explain.js +4 -1
- package/dist/commands/tasks/tasks-cli.js +31 -9
- package/dist/commands/tasks/tasks.js +239 -194
- package/dist/commands/tasks/validate.js +20 -32
- package/dist/core/activation-policy.js +4 -4
- package/dist/core/adapter/adapters/akm-adapter.js +5 -0
- package/dist/core/adapter/execution-source.js +10 -29
- package/dist/core/config/config-schema.js +64 -8
- package/dist/core/config/config-sources.js +96 -2
- package/dist/core/config/config.js +190 -24
- package/dist/core/config/legacy-source-shape-shim.js +9 -0
- package/dist/core/config/schema/execution.js +23 -0
- package/dist/core/config/schema/experimental.js +1 -1
- package/dist/core/config/schema/scheduler.js +20 -0
- package/dist/core/config/schema/search.js +1 -1
- package/dist/core/config/schema/sources-bundles.js +32 -1
- package/dist/core/content-safety.js +52 -0
- package/dist/core/maintenance-barrier.js +6 -6
- package/dist/core/type-presentation.js +1 -1
- package/dist/core/write-source.js +13 -8
- package/dist/indexer/bundle-identity-guard.js +45 -8
- package/dist/indexer/indexer.js +1 -1
- package/dist/indexer/materialize-embeddings.js +15 -1
- package/dist/indexer/search/search-source.js +29 -11
- package/dist/integrations/agent/execution-lowering.js +3 -2
- package/dist/integrations/agent/execution-preparation.js +32 -1
- package/dist/integrations/agent/prompts.js +1 -1
- package/dist/integrations/agent/request-lowering.js +3 -2
- package/dist/llm/client.js +2 -1
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/registry/resolve.js +37 -10
- package/dist/scripts/akm-migrate-node.js +13644 -9894
- package/dist/scripts/akm-migrate.js +12626 -8876
- package/dist/setup/setup.js +3 -3
- package/dist/setup/steps/tasks.js +29 -36
- package/dist/sources/providers/git-install.js +17 -11
- package/dist/sources/providers/git-provider.js +12 -5
- package/dist/sources/providers/git-stash.js +38 -16
- package/dist/sources/snapshot-fetchers/website-ingest.js +3 -3
- package/dist/storage/repositories/index-vec-repository.js +100 -0
- package/dist/tasks/activation-config.js +90 -0
- package/dist/tasks/backends/cron.js +9 -0
- package/dist/tasks/backends/launchd.js +1 -0
- package/dist/tasks/backends/schtasks.js +2 -0
- package/dist/tasks/embedded.js +4 -5
- package/dist/tasks/scheduler-binding.js +2 -2
- package/dist/tasks/scheduler-sync-preview.js +8 -1
- package/dist/tasks/scheduler-sync.js +19 -10
- package/dist/tasks/source/parse-task-source.js +10 -113
- package/dist/tasks/source/project-v4.js +2 -2
- package/dist/tasks/source/task-source-v4.js +4 -12
- package/dist/tasks/source/task-to-v3.js +4 -12
- package/dist/tasks/source/task-to-v4.js +40 -7
- package/docs/migration/README.md +1 -0
- package/docs/migration/release-notes/0.9.16.md +72 -0
- package/docs/migration/v0.9.1-to-v0.9.2.md +6 -9
- package/docs/reference/cli.md +37 -29
- package/docs/reference/configuration.md +48 -5
- package/docs/reference/tasks.md +34 -29
- package/package.json +1 -1
- package/schemas/akm-config.json +112 -4
- package/schemas/akm-task.json +1 -2
|
@@ -6,7 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
7
7
|
import { isBundleSlug } from "../../core/asset/asset-ref.js";
|
|
8
8
|
import { isHttpUrl, resolveStashDir } from "../../core/common.js";
|
|
9
|
-
import { bundleEntryToSourceEntry, getSources, installedSourceDescriptor, loadConfig, mutateConfig, } from "../../core/config/config.js";
|
|
9
|
+
import { bundleEntryToSourceEntry, getSources, installedSourceDescriptor, loadConfig, mutateConfig, resolveSecret, } from "../../core/config/config.js";
|
|
10
10
|
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
11
11
|
import { akmIndex } from "../../indexer/indexer.js";
|
|
12
12
|
import { deriveBundleId } from "../../indexer/installations.js";
|
|
@@ -16,7 +16,8 @@ import { detectStashRoot } from "../../sources/providers/provider-utils.js";
|
|
|
16
16
|
import { syncFromRef } from "../../sources/providers/sync-from-ref.js";
|
|
17
17
|
import { storeSecretResolver } from "../../sources/snapshot-fetchers/secret-seam.js";
|
|
18
18
|
import { ensureWebsiteMirror, shouldAllowPrivateWebsiteUrlForTests, validateWebsiteInputUrl, } from "../../sources/snapshot-fetchers/website-ingest.js";
|
|
19
|
-
import {
|
|
19
|
+
import { revokeSchedulerActivationsForBundle } from "../../tasks/activation-config.js";
|
|
20
|
+
import { bundleKeyForPath, bundleKeyForUrl, nextBundleKey, placeBundle, } from "./bundle-config-ops.js";
|
|
20
21
|
export async function akmAdd(input) {
|
|
21
22
|
const ref = input.ref.trim();
|
|
22
23
|
if (!ref)
|
|
@@ -24,23 +25,23 @@ export async function akmAdd(input) {
|
|
|
24
25
|
"Examples: `akm bundle add @scope/stash`, `akm bundle add github:owner/repo`, `akm bundle add ./local/path`");
|
|
25
26
|
const stashDir = resolveStashDir();
|
|
26
27
|
if (shouldAddAsWebsiteUrl(ref)) {
|
|
27
|
-
return addWebsiteSource(ref, stashDir, input.name, input.options);
|
|
28
|
+
return addWebsiteSource(ref, stashDir, input.name, input.options, input);
|
|
28
29
|
}
|
|
29
30
|
// Local directories become filesystem bundles; registry refs use the
|
|
30
31
|
// registry-backed bundle installer below.
|
|
31
32
|
try {
|
|
32
33
|
const parsed = parseRegistryRef(ref);
|
|
33
34
|
if (parsed.source === "local") {
|
|
34
|
-
return addLocalSource(ref, parsed.sourcePath, stashDir, input.name, input.adapter);
|
|
35
|
+
return addLocalSource(ref, parsed.sourcePath, stashDir, input.name, input.adapter, input);
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
38
|
catch {
|
|
38
39
|
// Not a local ref — fall through to registry install
|
|
39
40
|
}
|
|
40
|
-
return addRegistryStash(ref, stashDir, input.writable);
|
|
41
|
+
return addRegistryStash(ref, stashDir, input.writable, input, input.credential);
|
|
41
42
|
}
|
|
42
43
|
/** Add a local directory as a filesystem bundle. */
|
|
43
|
-
async function addLocalSource(ref, sourcePath, stashDir, explicitName, explicitAdapter) {
|
|
44
|
+
async function addLocalSource(ref, sourcePath, stashDir, explicitName, explicitAdapter, position = {}) {
|
|
44
45
|
const stashRoot = detectStashRoot(sourcePath);
|
|
45
46
|
const resolvedPath = path.resolve(stashRoot);
|
|
46
47
|
const adapter = explicitAdapter ?? detectAdapterId(resolvedPath);
|
|
@@ -62,11 +63,11 @@ async function addLocalSource(ref, sourcePath, stashDir, explicitName, explicitA
|
|
|
62
63
|
}
|
|
63
64
|
const bundles = { ...(config.bundles ?? {}) };
|
|
64
65
|
bundleKey = nextBundleKey(bundles, explicitName, resolvedPath);
|
|
65
|
-
|
|
66
|
+
const entry = {
|
|
66
67
|
path: resolvedPath,
|
|
67
68
|
components: { main: { root: ".", adapter } },
|
|
68
69
|
};
|
|
69
|
-
return { ...config, bundles };
|
|
70
|
+
return { ...config, bundles: placeBundle(bundles, bundleKey, entry, position) };
|
|
70
71
|
});
|
|
71
72
|
const index = await akmIndex({ stashDir });
|
|
72
73
|
const updatedConfig = loadConfig();
|
|
@@ -92,7 +93,7 @@ async function addLocalSource(ref, sourcePath, stashDir, explicitName, explicitA
|
|
|
92
93
|
},
|
|
93
94
|
};
|
|
94
95
|
}
|
|
95
|
-
async function addWebsiteSource(ref, stashDir, name, options) {
|
|
96
|
+
async function addWebsiteSource(ref, stashDir, name, options, position = {}) {
|
|
96
97
|
const allowPrivateHosts = shouldAllowPrivateWebsiteUrlForTests(ref);
|
|
97
98
|
const normalizedUrl = validateWebsiteInputUrl(ref, { allowPrivateHosts });
|
|
98
99
|
const numberOption = (value) => (typeof value === "number" ? value : undefined);
|
|
@@ -124,9 +125,9 @@ async function addWebsiteSource(ref, stashDir, name, options) {
|
|
|
124
125
|
entry = bundleEntryToSourceEntry(key, bundles[key]);
|
|
125
126
|
return config;
|
|
126
127
|
}
|
|
127
|
-
bundles
|
|
128
|
+
const nextBundles = placeBundle(bundles, key, nextBundle, position);
|
|
128
129
|
entry = bundleEntryToSourceEntry(key, nextBundle);
|
|
129
|
-
return { ...config, bundles };
|
|
130
|
+
return { ...config, bundles: nextBundles };
|
|
130
131
|
});
|
|
131
132
|
const cachePaths = await ensureWebsiteMirror(entry, {
|
|
132
133
|
requireStashDir: true,
|
|
@@ -161,11 +162,14 @@ async function addWebsiteSource(ref, stashDir, name, options) {
|
|
|
161
162
|
* Install a stash from a registry (npm, github, git) by dispatching to the
|
|
162
163
|
* matching syncable provider and persisting the lock entry.
|
|
163
164
|
*/
|
|
164
|
-
async function addRegistryStash(ref, stashDir, writable) {
|
|
165
|
+
async function addRegistryStash(ref, stashDir, writable, position = {}, credentialRef) {
|
|
165
166
|
const parsedRef = parseRegistryRef(ref);
|
|
166
167
|
if (writable === true && parsedRef.source !== "git" && parsedRef.source !== "github") {
|
|
167
168
|
throw new ConfigError("writable: true is only supported on filesystem and git sources", "INVALID_CONFIG_FILE");
|
|
168
169
|
}
|
|
170
|
+
if (credentialRef && parsedRef.source !== "git" && parsedRef.source !== "github") {
|
|
171
|
+
throw new ConfigError("credential is only supported on git sources", "INVALID_CONFIG_FILE");
|
|
172
|
+
}
|
|
169
173
|
const currentConfig = loadConfig();
|
|
170
174
|
const existingBundleKey = findInstalledBundleKey(currentConfig.bundles ?? {}, parsedRef.id);
|
|
171
175
|
const existingBundle = existingBundleKey ? currentConfig.bundles?.[existingBundleKey] : undefined;
|
|
@@ -179,6 +183,11 @@ async function addRegistryStash(ref, stashDir, writable) {
|
|
|
179
183
|
writable: effectiveWritable,
|
|
180
184
|
...(effectiveWritable && priorLock?.localRoot ? { writableRoot: priorLock.localRoot } : {}),
|
|
181
185
|
...(requiredRoots.length > 0 ? { writableRequiredRoots: requiredRoots } : {}),
|
|
186
|
+
...(credentialRef
|
|
187
|
+
? { credential: resolveSecret(credentialRef, storeSecretResolver.resolveSecret) }
|
|
188
|
+
: existingBundle?.credential
|
|
189
|
+
? { credential: resolveSecret(existingBundle.credential, storeSecretResolver.resolveSecret) }
|
|
190
|
+
: {}),
|
|
182
191
|
});
|
|
183
192
|
const { config: updatedConfig, bundleId } = upsertInstalledRegistryEntry({
|
|
184
193
|
id: synced.id,
|
|
@@ -191,7 +200,7 @@ async function addRegistryStash(ref, stashDir, writable) {
|
|
|
191
200
|
cacheDir: synced.cacheDir,
|
|
192
201
|
installedAt: synced.syncedAt,
|
|
193
202
|
writable: synced.writable,
|
|
194
|
-
});
|
|
203
|
+
}, position, credentialRef);
|
|
195
204
|
// The prior materialized root (if this is a re-install) — read BEFORE the lock
|
|
196
205
|
// upsert overwrites it, so a moved cache root can be cleaned afterwards.
|
|
197
206
|
const priorLocalRoot = priorLock?.localRoot;
|
|
@@ -252,7 +261,7 @@ async function addRegistryStash(ref, stashDir, writable) {
|
|
|
252
261
|
* via {@link upsertLockEntry} with the returned `bundleId`). Returns the config
|
|
253
262
|
* plus the derived bundle id so the caller keys its lock entry identically.
|
|
254
263
|
*/
|
|
255
|
-
export function upsertInstalledRegistryEntry(entry) {
|
|
264
|
+
export function upsertInstalledRegistryEntry(entry, position = {}, credential) {
|
|
256
265
|
let bundleId = entry.id;
|
|
257
266
|
const config = mutateConfig((current) => {
|
|
258
267
|
const bundles = { ...(current.bundles ?? {}) };
|
|
@@ -271,13 +280,15 @@ export function upsertInstalledRegistryEntry(entry) {
|
|
|
271
280
|
},
|
|
272
281
|
};
|
|
273
282
|
const descriptor = installedSourceDescriptor(entry.source, entry.ref, path.resolve(entry.stashRoot));
|
|
274
|
-
bundles[bundleId]
|
|
283
|
+
const effectiveCredential = credential ?? bundles[bundleId]?.credential;
|
|
284
|
+
const nextEntry = {
|
|
275
285
|
...descriptor,
|
|
286
|
+
...(effectiveCredential ? { credential: effectiveCredential } : {}),
|
|
276
287
|
...(entry.writable === true ? { writable: true } : {}),
|
|
277
288
|
...(entry.id !== bundleId ? { registryId: entry.id } : {}),
|
|
278
289
|
components: components,
|
|
279
290
|
};
|
|
280
|
-
return { ...current, bundles };
|
|
291
|
+
return { ...current, bundles: placeBundle(bundles, bundleId, nextEntry, position) };
|
|
281
292
|
}).config;
|
|
282
293
|
return { config, bundleId };
|
|
283
294
|
}
|
|
@@ -295,7 +306,12 @@ export async function removeInstalledRegistryEntry(id) {
|
|
|
295
306
|
return current;
|
|
296
307
|
removedKey = key;
|
|
297
308
|
delete bundles[key];
|
|
298
|
-
return {
|
|
309
|
+
return revokeSchedulerActivationsForBundle({
|
|
310
|
+
...current,
|
|
311
|
+
bundles: Object.keys(bundles).length > 0 ? bundles : undefined,
|
|
312
|
+
...(current.defaultBundle === key ? { defaultBundle: undefined } : {}),
|
|
313
|
+
...(current.defaultWriteTarget === key ? { defaultWriteTarget: undefined } : {}),
|
|
314
|
+
}, key);
|
|
299
315
|
}).config;
|
|
300
316
|
if (removedKey)
|
|
301
317
|
await removeLockEntry(removedKey);
|
|
@@ -6,7 +6,8 @@ import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
|
6
6
|
import { isRemoteUrl } from "../../core/common.js";
|
|
7
7
|
import { bundleEntryToSourceEntry, bundlesToSourceEntries, getSources, mutateConfig } from "../../core/config/config.js";
|
|
8
8
|
import { ConfigError, UsageError } from "../../core/errors.js";
|
|
9
|
-
import {
|
|
9
|
+
import { revokeSchedulerActivationsForBundle } from "../../tasks/activation-config.js";
|
|
10
|
+
import { bundleKeyForPath, bundleKeyForUrl, nextBundleKey, placeBundle, } from "./bundle-config-ops.js";
|
|
10
11
|
// ── Operations ──────────────────────────────────────────────────────────────
|
|
11
12
|
/**
|
|
12
13
|
* Add a stash source (filesystem path or remote provider URL) to config.
|
|
@@ -16,13 +17,16 @@ import { bundleKeyForPath, bundleKeyForUrl, nextBundleKey } from "./bundle-confi
|
|
|
16
17
|
* (e.g. "website", "git").
|
|
17
18
|
*/
|
|
18
19
|
export function addStash(opts) {
|
|
19
|
-
const { target, name, providerType, options: providerOptions, writable } = opts;
|
|
20
|
+
const { target, name, providerType, options: providerOptions, writable, credential, before, after } = opts;
|
|
20
21
|
if (providerType === "openviking") {
|
|
21
22
|
throw new ConfigError("openviking is not supported in akm v1.", "INVALID_CONFIG_FILE");
|
|
22
23
|
}
|
|
23
24
|
if (writable === true && providerType && providerType !== "filesystem" && providerType !== "git") {
|
|
24
25
|
throw new ConfigError("writable: true is only supported on filesystem and git sources", "INVALID_CONFIG_FILE");
|
|
25
26
|
}
|
|
27
|
+
if (credential && providerType !== "git") {
|
|
28
|
+
throw new ConfigError("credential is only supported on git sources", "INVALID_CONFIG_FILE");
|
|
29
|
+
}
|
|
26
30
|
let result;
|
|
27
31
|
const targetIsUrl = isRemoteUrl(target);
|
|
28
32
|
if (targetIsUrl && !providerType) {
|
|
@@ -53,7 +57,15 @@ export function addStash(opts) {
|
|
|
53
57
|
return config;
|
|
54
58
|
}
|
|
55
59
|
key = nextBundleKey(bundles, name, target);
|
|
56
|
-
|
|
60
|
+
const entry = urlBundleDescriptor(providerType, target, providerOptions, writable === true, credential);
|
|
61
|
+
const nextBundles = placeBundle(bundles, key, entry, { before, after });
|
|
62
|
+
const next = { ...config, bundles: nextBundles };
|
|
63
|
+
result = {
|
|
64
|
+
sources: bundlesToSourceEntries(next) ?? [],
|
|
65
|
+
added: true,
|
|
66
|
+
entry: bundleEntryToSourceEntry(key, entry),
|
|
67
|
+
};
|
|
68
|
+
return next;
|
|
57
69
|
}
|
|
58
70
|
else {
|
|
59
71
|
const resolvedPath = path.resolve(target);
|
|
@@ -62,18 +74,22 @@ export function addStash(opts) {
|
|
|
62
74
|
return config;
|
|
63
75
|
}
|
|
64
76
|
key = nextBundleKey(bundles, name, resolvedPath);
|
|
65
|
-
|
|
77
|
+
const entry = {
|
|
66
78
|
path: resolvedPath,
|
|
67
79
|
...(writable === true ? { writable: true } : {}),
|
|
68
80
|
components: {
|
|
69
81
|
main: { root: ".", adapter: detectAdapterId(resolvedPath), writable: writable ?? true },
|
|
70
82
|
},
|
|
71
83
|
};
|
|
84
|
+
const nextBundles = placeBundle(bundles, key, entry, { before, after });
|
|
85
|
+
const next = { ...config, bundles: nextBundles };
|
|
86
|
+
result = {
|
|
87
|
+
sources: bundlesToSourceEntries(next) ?? [],
|
|
88
|
+
added: true,
|
|
89
|
+
entry: bundleEntryToSourceEntry(key, entry),
|
|
90
|
+
};
|
|
91
|
+
return next;
|
|
72
92
|
}
|
|
73
|
-
const next = { ...config, bundles };
|
|
74
|
-
const entry = bundleEntryToSourceEntry(key, bundles[key]);
|
|
75
|
-
result = { sources: bundlesToSourceEntries(next) ?? [], added: true, entry };
|
|
76
|
-
return next;
|
|
77
93
|
});
|
|
78
94
|
return result;
|
|
79
95
|
}
|
|
@@ -83,7 +99,7 @@ export function addStash(opts) {
|
|
|
83
99
|
* package spec (e.g. "lodash", "@scope/pkg@^2") — never a URL (R-013,
|
|
84
100
|
* rejected earlier in {@link addStash}).
|
|
85
101
|
*/
|
|
86
|
-
function urlBundleDescriptor(providerType, locator, options, writable) {
|
|
102
|
+
function urlBundleDescriptor(providerType, locator, options, writable, credential) {
|
|
87
103
|
if (providerType === "website") {
|
|
88
104
|
// Website provider options ride on the (passthrough) website descriptor and
|
|
89
105
|
// round-trip back to `entry.options` via bundleEntryToSourceEntry.
|
|
@@ -94,8 +110,9 @@ function urlBundleDescriptor(providerType, locator, options, writable) {
|
|
|
94
110
|
}
|
|
95
111
|
if (providerType === "npm")
|
|
96
112
|
return { npm: locator };
|
|
97
|
-
if (providerType === "git")
|
|
98
|
-
return { git: locator, ...(writable ? { writable: true } : {}) };
|
|
113
|
+
if (providerType === "git") {
|
|
114
|
+
return { git: locator, ...(writable ? { writable: true } : {}), ...(credential ? { credential } : {}) };
|
|
115
|
+
}
|
|
99
116
|
throw new ConfigError(`unsupported source type "${providerType}"; expected filesystem, git, website, or npm`, "INVALID_CONFIG_FILE");
|
|
100
117
|
}
|
|
101
118
|
/**
|
|
@@ -120,7 +137,12 @@ export function removeStash(target) {
|
|
|
120
137
|
}
|
|
121
138
|
const removed = bundleEntryToSourceEntry(key, bundles[key]);
|
|
122
139
|
delete bundles[key];
|
|
123
|
-
const next = {
|
|
140
|
+
const next = revokeSchedulerActivationsForBundle({
|
|
141
|
+
...config,
|
|
142
|
+
bundles: Object.keys(bundles).length > 0 ? bundles : undefined,
|
|
143
|
+
...(config.defaultBundle === key ? { defaultBundle: undefined } : {}),
|
|
144
|
+
...(config.defaultWriteTarget === key ? { defaultWriteTarget: undefined } : {}),
|
|
145
|
+
}, key);
|
|
124
146
|
result = { sources: bundlesToSourceEntries(next) ?? [], removed: true, entry: removed };
|
|
125
147
|
return next;
|
|
126
148
|
});
|
|
@@ -73,6 +73,8 @@ export function scaffoldStashMeta(stashDir) {
|
|
|
73
73
|
}
|
|
74
74
|
/** Marks the akm-authored block in a stash `.gitignore` (idempotency anchor). */
|
|
75
75
|
const STASH_GITIGNORE_MARKER = "# akm: keep secret material out of git by default";
|
|
76
|
+
/** Documented opt-out for private bundles that deliberately version env/ and secrets/. */
|
|
77
|
+
export const STASH_GITIGNORE_TRACK_SECRETS_MARKER = "# akm: intentionally track env and secrets";
|
|
76
78
|
const STASH_GITIGNORE_BLOCK = [
|
|
77
79
|
STASH_GITIGNORE_MARKER,
|
|
78
80
|
"# env/ and secrets/ assets hold tokens and keys. They are ignored by default",
|
|
@@ -89,14 +91,15 @@ const STASH_GITIGNORE_BLOCK = [
|
|
|
89
91
|
*
|
|
90
92
|
* Idempotent + non-clobbering: creates the file when absent, appends the akm
|
|
91
93
|
* block when the file exists but lacks it (preserving the user's own rules),
|
|
92
|
-
* and no-ops once the marker is present.
|
|
93
|
-
*
|
|
94
|
+
* and no-ops once the marker is present. A private bundle that deliberately
|
|
95
|
+
* versions all secret material can add `# akm: intentionally track env and
|
|
96
|
+
* secrets`; that explicit marker suppresses this helper entirely (#981).
|
|
94
97
|
*/
|
|
95
98
|
export function ensureStashGitignore(stashDir) {
|
|
96
99
|
try {
|
|
97
100
|
const gitignorePath = path.join(stashDir, ".gitignore");
|
|
98
101
|
const existing = fs.existsSync(gitignorePath) ? fs.readFileSync(gitignorePath, "utf8") : "";
|
|
99
|
-
if (existing.includes(STASH_GITIGNORE_MARKER))
|
|
102
|
+
if (existing.includes(STASH_GITIGNORE_MARKER) || existing.includes(STASH_GITIGNORE_TRACK_SECRETS_MARKER))
|
|
100
103
|
return;
|
|
101
104
|
const gap = existing.length === 0 ? "" : existing.endsWith("\n") ? "\n" : "\n\n";
|
|
102
105
|
fs.writeFileSync(gitignorePath, `${existing}${gap}${STASH_GITIGNORE_BLOCK}`);
|
|
@@ -77,12 +77,14 @@
|
|
|
77
77
|
*/
|
|
78
78
|
import fs from "node:fs";
|
|
79
79
|
import { detectAdapterId } from "../../core/adapter/detect-adapter.js";
|
|
80
|
+
import { makeBundleRef } from "../../core/asset/asset-ref.js";
|
|
80
81
|
import { loadConfig } from "../../core/config/config.js";
|
|
81
82
|
import { NotFoundError } from "../../core/errors.js";
|
|
82
83
|
import { applyInputDefaults, materializeInputFlags, } from "../../execution/input-contract.js";
|
|
83
84
|
import { createInlineResolvedCommand } from "../../execution/resolved-request.js";
|
|
84
85
|
import { resolveAdapterConceptOwner } from "../../indexer/lookup/adapter-concept-owner.js";
|
|
85
86
|
import { prepareResolvedExecution } from "../../integrations/agent/execution-preparation.js";
|
|
87
|
+
import { isSchedulerRefEnabled } from "../../tasks/activation-config.js";
|
|
86
88
|
import { parseTaskSource } from "../../tasks/source/parse-task-source.js";
|
|
87
89
|
import { projectTaskSourceV4 } from "../../tasks/source/project-v4.js";
|
|
88
90
|
import { TASK_INPUT_DIAGNOSTICS } from "../../tasks/source/task-input-diagnostics.js";
|
|
@@ -270,10 +272,11 @@ export async function akmTaskExplain(ref, options = {}) {
|
|
|
270
272
|
const materializedInputs = materializeInputFlags(inputContract, options.inputFlags ?? [], TASK_INPUT_DIAGNOSTICS);
|
|
271
273
|
const defaultedInputs = applyInputDefaults(inputContract, materializedInputs);
|
|
272
274
|
const document = projectTaskSourceV4(parsed.v4);
|
|
275
|
+
const enabled = isSchedulerRefEnabled(loadConfig(), "task", makeBundleRef(bundle.source.name, taskConceptId));
|
|
273
276
|
const schedule = parsed.v4.schedule.map((entry) => ({
|
|
274
277
|
ordinal: entry.ordinal,
|
|
275
278
|
cron: entry.cron,
|
|
276
|
-
enabled
|
|
279
|
+
enabled,
|
|
277
280
|
source: entry.source,
|
|
278
281
|
inputs: Object.fromEntries(Object.entries(entry.inputs).map(([name, value]) => {
|
|
279
282
|
const redaction = redactIfSecretShaped(name, value);
|
|
@@ -12,13 +12,11 @@
|
|
|
12
12
|
* that would skip pending cleanup).
|
|
13
13
|
*
|
|
14
14
|
* 0.9 CLI overhaul (S6): the group was renamed from the plural `tasks` to the
|
|
15
|
-
* singular `task` — hard break, no alias. `init
|
|
16
|
-
* dropped: the default improve-schedule task set now ships as embedded
|
|
15
|
+
* singular `task` — hard break, no alias. `init` was dropped: the default improve-schedule task set now ships as embedded
|
|
17
16
|
* templates under src/assets/tasks/improve/ (see src/tasks/embedded.ts),
|
|
18
17
|
* seeded through the interactive `akm setup` task-review step instead of a
|
|
19
|
-
* separate CLI command
|
|
20
|
-
*
|
|
21
|
-
* subcommand (`add`/`run`/`history`/`sync`) shares one `--bundle <bundle>`
|
|
18
|
+
* separate CLI command. `enable`/`disable` mutate the host-local scheduler
|
|
19
|
+
* allow-list, never the task source. Every subcommand shares one `--bundle <bundle>`
|
|
22
20
|
* axis (S8.4 ratified `task add`'s `--target` → `--bundle`; a later Gate-1
|
|
23
21
|
* fix reverted it to match `import`/`proposal accept`, splitting the
|
|
24
22
|
* write-target axis three-vs-one against `remember`/`clone`/`improve` — the
|
|
@@ -35,7 +33,7 @@ import { TASK_RUN_BOOLEAN_FLAGS, TASK_RUN_VALUE_FLAGS } from "../../tasks/task-r
|
|
|
35
33
|
import { akmSearch, parseSearchSource } from "../read/search.js";
|
|
36
34
|
import { rejectRetiredSourceFlag } from "../read/search-cli.js";
|
|
37
35
|
import { akmTaskExplain } from "./explain.js";
|
|
38
|
-
import { akmTasksAdd, akmTasksDoctor, akmTasksHistory, akmTasksPrune, akmTasksRun, akmTasksSync, akmTasksSyncPlan, } from "./tasks.js";
|
|
36
|
+
import { akmTasksAdd, akmTasksDisable, akmTasksDoctor, akmTasksEnable, akmTasksHistory, akmTasksPrune, akmTasksRun, akmTasksSync, akmTasksSyncPlan, } from "./tasks.js";
|
|
39
37
|
import { akmTaskValidate } from "./validate.js";
|
|
40
38
|
/** Shared `--bundle <bundle>` arg wired onto every task subcommand. */
|
|
41
39
|
const bundleArg = {
|
|
@@ -294,6 +292,28 @@ const tasksRunCommand = defineCommand({
|
|
|
294
292
|
});
|
|
295
293
|
},
|
|
296
294
|
});
|
|
295
|
+
const tasksEnableCommand = defineJsonCommand({
|
|
296
|
+
meta: { name: "enable", description: "Enable a task in this host's scheduler configuration and sync it" },
|
|
297
|
+
args: {
|
|
298
|
+
ref: { type: "positional", description: "Task ref or id", required: true },
|
|
299
|
+
...bundleArg,
|
|
300
|
+
},
|
|
301
|
+
async run({ args }) {
|
|
302
|
+
rejectRetiredTaskTargetFlag();
|
|
303
|
+
output("task-enable", await akmTasksEnable(args.ref, { target: args.bundle }));
|
|
304
|
+
},
|
|
305
|
+
});
|
|
306
|
+
const tasksDisableCommand = defineJsonCommand({
|
|
307
|
+
meta: { name: "disable", description: "Disable a task in this host's scheduler configuration and sync it" },
|
|
308
|
+
args: {
|
|
309
|
+
ref: { type: "positional", description: "Task ref or id", required: true },
|
|
310
|
+
...bundleArg,
|
|
311
|
+
},
|
|
312
|
+
async run({ args }) {
|
|
313
|
+
rejectRetiredTaskTargetFlag();
|
|
314
|
+
output("task-disable", await akmTasksDisable(args.ref, { target: args.bundle }));
|
|
315
|
+
},
|
|
316
|
+
});
|
|
297
317
|
/**
|
|
298
318
|
* #911: `task run <id>` and `task explain <ref>` take the id positionally, so
|
|
299
319
|
* `task history <id>` is the natural thing to write — and it used to be
|
|
@@ -415,8 +435,8 @@ const tasksDoctorCommand = defineJsonCommand({
|
|
|
415
435
|
},
|
|
416
436
|
});
|
|
417
437
|
/**
|
|
418
|
-
* #907: `akm task validate`'s exit-code contract —
|
|
419
|
-
* successful
|
|
438
|
+
* #907: `akm task validate`'s exit-code contract — only current-schema
|
|
439
|
+
* `valid` is successful (exit 0); `blocked`/`invalid`/`not-a-task` are
|
|
420
440
|
* diagnosed defects the caller must act on (exit 1, mirroring `task sync`'s
|
|
421
441
|
* own `failures.length > 0 -> EXIT_CODES.GENERAL`). A missing path or an
|
|
422
442
|
* unreadable file never reaches this function at all — `akmTaskValidate`
|
|
@@ -424,7 +444,7 @@ const tasksDoctorCommand = defineJsonCommand({
|
|
|
424
444
|
* already maps to exit 2.
|
|
425
445
|
*/
|
|
426
446
|
export function taskValidateExitCode(result) {
|
|
427
|
-
return result.outcome === "valid"
|
|
447
|
+
return result.outcome === "valid" ? undefined : EXIT_CODES.GENERAL;
|
|
428
448
|
}
|
|
429
449
|
const tasksValidateCommand = defineJsonCommand({
|
|
430
450
|
meta: {
|
|
@@ -532,6 +552,8 @@ export const taskCommand = defineGroupCommand({
|
|
|
532
552
|
},
|
|
533
553
|
subCommands: {
|
|
534
554
|
add: tasksAddCommand,
|
|
555
|
+
enable: tasksEnableCommand,
|
|
556
|
+
disable: tasksDisableCommand,
|
|
535
557
|
run: tasksRunCommand,
|
|
536
558
|
explain: tasksExplainCommand,
|
|
537
559
|
validate: tasksValidateCommand,
|