@asc-agent/runtime 0.2.1 โ 0.3.1
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/README.md +25 -25
- package/dist/adapters/claude-code/skill.js +259 -239
- package/dist/adapters/gitlab/adapter.d.ts +3 -0
- package/dist/adapters/gitlab/adapter.js +22 -3
- package/dist/adapters/gitlab/client.d.ts +27 -1
- package/dist/adapters/gitlab/client.js +30 -0
- package/dist/adapters/gitlab/ports.d.ts +3 -3
- package/dist/adapters/jam/adapter.d.ts +14 -0
- package/dist/adapters/jam/adapter.js +84 -6
- package/dist/adapters/jam/ports.d.ts +9 -0
- package/dist/adapters/jam/ports.js +49 -2
- package/dist/adapters/local/repo.d.ts +15 -0
- package/dist/adapters/local/repo.js +238 -0
- package/dist/adapters/markdown/state-store.js +13 -1
- package/dist/adapters/memory/state-store.js +4 -0
- package/dist/cli/asc.js +485 -10
- package/dist/composition/propose.d.ts +19 -0
- package/dist/composition/propose.js +35 -0
- package/dist/composition/runtime.d.ts +2 -0
- package/dist/composition/runtime.js +41 -5
- package/dist/core/attach/init.d.ts +17 -0
- package/dist/core/attach/init.js +28 -0
- package/dist/core/distribution/node-runtime.d.ts +29 -0
- package/dist/core/distribution/node-runtime.js +35 -0
- package/dist/core/distribution/release.d.ts +3 -3
- package/dist/core/distribution/release.js +1 -1
- package/dist/core/monitor/investigation.d.ts +16 -0
- package/dist/core/monitor/investigation.js +18 -9
- package/dist/core/operator/contract-draft.d.ts +124 -0
- package/dist/core/operator/contract-draft.js +234 -0
- package/dist/core/operator/derive-draft.d.ts +37 -0
- package/dist/core/operator/derive-draft.js +216 -0
- package/dist/core/operator/proceed.d.ts +79 -0
- package/dist/core/operator/proceed.js +123 -1
- package/dist/core/operator/work-state.d.ts +60 -0
- package/dist/core/operator/work-state.js +181 -0
- package/dist/core/runtime/closure.d.ts +2 -2
- package/dist/ports/local-repo.d.ts +84 -0
- package/dist/ports/local-repo.js +9 -0
- package/dist/ports/resource-context.d.ts +7 -0
- package/dist/schemas/profile.d.ts +2 -2
- package/package.json +3 -3
package/dist/cli/asc.js
CHANGED
|
@@ -9,17 +9,19 @@
|
|
|
9
9
|
import { execFile, spawnSync } from 'node:child_process';
|
|
10
10
|
import { parseArgs, promisify } from 'node:util';
|
|
11
11
|
import { existsSync, readdirSync, realpathSync } from 'node:fs';
|
|
12
|
-
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
12
|
+
import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
13
13
|
import { fileURLToPath } from 'node:url';
|
|
14
|
-
import { homedir } from 'node:os';
|
|
14
|
+
import { homedir, userInfo } from 'node:os';
|
|
15
15
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
16
|
-
import { MINIMUM_NODE_MAJOR, checkNodeRuntime, } from "../core/distribution/node-runtime.js";
|
|
16
|
+
import { MINIMUM_NODE_MAJOR, checkNodeRuntime, reexecWithCandidate, } from "../core/distribution/node-runtime.js";
|
|
17
|
+
import { RELEASE_VERSION } from "../core/distribution/release.js";
|
|
17
18
|
import { GitHubClient, discoverToken } from "../adapters/github/client.js";
|
|
18
19
|
import { GitHubChangeContext, GitHubInventory, GitHubResourceContext } from "../adapters/github/context.js";
|
|
19
20
|
import { GitHubEventSource } from "../adapters/github/event-source.js";
|
|
20
21
|
import { GitHubScm } from "../adapters/github/scm.js";
|
|
21
22
|
import { MarkdownStateStore } from "../adapters/markdown/state-store.js";
|
|
22
23
|
import { LocalIdentityBinding } from "../adapters/local/identity.js";
|
|
24
|
+
import { IDENTITY_FILE } from "./identity-config.js";
|
|
23
25
|
import { TextRenderer } from "../adapters/text/renderer.js";
|
|
24
26
|
import { ApprovalService } from "../core/approval/service.js";
|
|
25
27
|
import { Executor } from "../core/execution/executor.js";
|
|
@@ -32,6 +34,7 @@ import { adoptionLine, judgeAdoption, migrate } from "../core/workspace/migrate.
|
|
|
32
34
|
import { newWorkspaceId, normalizeRemote, recoverCandidates, recoverLines } from "../core/workspace/identity.js";
|
|
33
35
|
import { resolveWorkspace, resolutionLine } from "../core/workspace/resolve.js";
|
|
34
36
|
import { assessSetup, renderSetup } from "../core/attach/setup.js";
|
|
37
|
+
import { withIdentity } from "../core/attach/init.js";
|
|
35
38
|
import { applySetupPlan, computeSetupPlan, renderSetupPlan, } from "../core/attach/setup-plan.js";
|
|
36
39
|
import { CLAUDE_PROVIDER, CLAUDE_SCOPE, claudeBindings } from "../adapters/claude-code/binding.js";
|
|
37
40
|
import { readHeartbeat } from "../adapters/claude-code/observer.js";
|
|
@@ -42,15 +45,23 @@ import { MonitorEngine } from "../core/monitor/engine.js";
|
|
|
42
45
|
import { CoverageLedger, renderHealth } from "../core/monitor/coverage.js";
|
|
43
46
|
import { evaluateHealth, healthAlertLines } from "../core/monitor/health-alerts.js";
|
|
44
47
|
import { Operator } from "../core/operator/proceed.js";
|
|
48
|
+
import { deriveSessionContractDraft } from "../core/operator/derive-draft.js";
|
|
49
|
+
import { LocalRepoAdapter } from "../adapters/local/repo.js";
|
|
50
|
+
import { GitHubAdapter } from "../adapters/github/adapter.js";
|
|
51
|
+
import { GitLabAdapter } from "../adapters/gitlab/adapter.js";
|
|
52
|
+
import { JamAdapter } from "../adapters/jam/adapter.js";
|
|
53
|
+
import { statusIndicatesDone } from "../adapters/jam/ports.js";
|
|
45
54
|
import { ProgressService } from "../core/operator/progress.js";
|
|
46
55
|
import { composeBindings, defaultAdapters } from "../composition/registry.js";
|
|
47
|
-
import { buildRuntimePorts, rolesFor } from "../composition/runtime.js";
|
|
56
|
+
import { buildRuntimePorts, closeToolClients, rolesFor } from "../composition/runtime.js";
|
|
57
|
+
import { proposeBindings } from "../composition/propose.js";
|
|
48
58
|
import { buildEventObservation } from "../composition/observe.js";
|
|
49
59
|
import { availableProfiles, planBootstrap, renderPlan } from "../core/attach/bootstrap.js";
|
|
50
60
|
import { detectStableInstall, installStableRuntime, verifyStableInstall, } from "../core/distribution/runtime-install.js";
|
|
51
61
|
import { readRuntimeSelection, remediationAction, remediationLines, resolveRuntimeTarget, runtimeSelectionLine, selectionPath, writeRuntimeSelection, } from "../core/distribution/runtime-select.js";
|
|
52
62
|
import { portableCommand, shorthandCommand } from "../core/distribution/release.js";
|
|
53
63
|
import { preflight } from "../core/operator/preflight.js";
|
|
64
|
+
import { DraftProvenance, issueArgs, planSessionContract, } from "../core/operator/contract-draft.js";
|
|
54
65
|
import { lookupAuthority } from "../core/policy/ownership.js";
|
|
55
66
|
import { renderProgress } from "../core/operator/render.js";
|
|
56
67
|
import { AuditLedger, decisionLines, delegationLine, executionLines, reclaimLine, validationLines, } from "../core/runtime/audit.js";
|
|
@@ -76,7 +87,7 @@ import { LocalOperator } from "../core/operator/local-operator.js";
|
|
|
76
87
|
import { loadIdentityMap } from "./identity-config.js";
|
|
77
88
|
const USAGE = `asc โ Agent Session Control
|
|
78
89
|
|
|
79
|
-
asc proceed [--session <id>] [--goal <text>] [--json]
|
|
90
|
+
asc proceed [--session <id>] [--work <WORK-ID>] [--goal <text>] [--json]
|
|
80
91
|
|
|
81
92
|
asc inbox list [--all] [--priority P0|P1|P2] [--json]
|
|
82
93
|
asc inbox show <REQUEST_ID> [--json]
|
|
@@ -121,11 +132,16 @@ const USAGE = `asc โ Agent Session Control
|
|
|
121
132
|
# without --profile: report what was detected, then stop
|
|
122
133
|
|
|
123
134
|
asc setup status [--json]
|
|
135
|
+
asc setup identity [--role controller|monitor|both] [--actor <channel:actor>]
|
|
136
|
+
# ์ง๊ธ ์ด ์ฌ๋์ ์น์ธ ๊ถํ์๋ก ์ธ์ฐ๊ณ ์ฌ๊ณ ์ ๊น์ง ํ๋ค
|
|
124
137
|
asc setup plan [--profile <id>] [--scope local|project] [--json]
|
|
125
138
|
# says what it would change โ changes nothing
|
|
126
139
|
asc setup apply [--profile <id>] [--scope local|project] [--json]
|
|
127
140
|
asc setup apply --json # non-interactive apply. stdout is a single JSON document
|
|
128
141
|
|
|
142
|
+
asc session plan [--id <S-ID>] [--role <role>] [--goal <text>] [--boundary <glob>...]
|
|
143
|
+
[--criteria <text>...] [--owner <role>] [--provenance <f>=<STATUS>[:<src>]...]
|
|
144
|
+
[--json] # is this draft issuable? changes nothing
|
|
129
145
|
asc session issue <ID> --role <role> --goal <text> [--block <id>]
|
|
130
146
|
[--parent <S-ID>] [--issued-by <principal>]
|
|
131
147
|
asc session pause <S-ID> --position <t> --next <t> [--physical <id>]
|
|
@@ -189,6 +205,8 @@ Options
|
|
|
189
205
|
--write actually write the artefacts (default: preview)
|
|
190
206
|
--role planner|researcher|implementer|verifier
|
|
191
207
|
--goal the single goal of this session
|
|
208
|
+
--work work item to investigate before proposing a contract (asc proceed)
|
|
209
|
+
--actor who you are, as <channel>:<actor> (asc setup identity)
|
|
192
210
|
--boundary write scope (must be narrower than the Profile's)
|
|
193
211
|
--exception SOFT DENY item allowed for this session only
|
|
194
212
|
--criteria a verifiable done-criterion (repeatable)
|
|
@@ -410,6 +428,8 @@ export async function runAscCommand(argv, entry = 'runtime') {
|
|
|
410
428
|
ownership: { type: 'string', multiple: true },
|
|
411
429
|
verification: { type: 'string', multiple: true },
|
|
412
430
|
why: { type: 'string', multiple: true },
|
|
431
|
+
/** ์ด์์ ์ถ์ฒ โ `<field>=<FACT|PROPOSAL|DECISION_REQUIRED>[:<source>]` (session plan). */
|
|
432
|
+
provenance: { type: 'string', multiple: true },
|
|
413
433
|
offline: { type: 'boolean', default: false },
|
|
414
434
|
id: { type: 'string' },
|
|
415
435
|
intent: { type: 'string' },
|
|
@@ -458,6 +478,8 @@ export async function runAscCommand(argv, entry = 'runtime') {
|
|
|
458
478
|
body: { type: 'string' },
|
|
459
479
|
to: { type: 'string' },
|
|
460
480
|
session: { type: 'string' },
|
|
481
|
+
work: { type: 'string' },
|
|
482
|
+
actor: { type: 'string' },
|
|
461
483
|
position: { type: 'string' },
|
|
462
484
|
next: { type: 'string' },
|
|
463
485
|
done: { type: 'string', multiple: true },
|
|
@@ -500,6 +522,17 @@ export async function runAscCommand(argv, entry = 'runtime') {
|
|
|
500
522
|
// ๋๋ฉด ๊ทธ์ชฝ์ ์ ์ฑ
์ด ์๊ธฐ๊ณ (C-14 ๋ถ๋ณ์ โฆ), ๊ทธ๋ฌ๋ฉด ๋ ์ง์
์ ๋ต์ด ๊ฐ๋ฆด ์ ์๋ค.
|
|
501
523
|
const runnable = await checkNodeRuntime(nodeRuntimeDeps());
|
|
502
524
|
if (!runnable.ok) {
|
|
525
|
+
// ํ๋ณด๋ฅผ ์ด๋ฏธ ์ฐพ์์ผ๋ฉด ์ฒ๋ฐฉ ๋์ ์คํํ๋ค โ ๊ฐ์ ๋ช
๋ น, ๊ฐ์ argv, ํธํ Node (A6).
|
|
526
|
+
const reexec = reexecWithCandidate(runnable, argv, {
|
|
527
|
+
env: process.env,
|
|
528
|
+
entry: fileURLToPath(import.meta.url),
|
|
529
|
+
spawn: (path, args, env) => {
|
|
530
|
+
const child = spawnSync(path, args, { stdio: 'inherit', env: env });
|
|
531
|
+
return { status: child.status, signal: child.signal, ...(child.error ? { error: child.error } : {}) };
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
if (reexec !== null)
|
|
535
|
+
return reexec;
|
|
503
536
|
reportNodeRuntime(runnable, Boolean(values.json) || Boolean(values.agent));
|
|
504
537
|
return 1;
|
|
505
538
|
}
|
|
@@ -986,7 +1019,9 @@ function declaredPolicies(resolved) {
|
|
|
986
1019
|
}
|
|
987
1020
|
return declared;
|
|
988
1021
|
}
|
|
989
|
-
|
|
1022
|
+
// RELEASE_VERSION ์ด ์ ๋ณธ์ด๋ค โ ์ฌ๊ธฐ ๋ฌธ์์ด์ ๋ฐ๋ก ๋๋ฉด ๋ฆด๋ฆฌ์ค๋ง๋ค ๋ก๋๋ค (0.3.0 ์์
|
|
1023
|
+
// 0.2.1 ๋ก ๋จ์ lock ์ ascVersion ํ๊ธฐ๊ฐ ์ค์ ์ ์ด๊ธ๋ฌ๋ค).
|
|
1024
|
+
const ASC_VERSION = RELEASE_VERSION;
|
|
990
1025
|
const CAPABILITIES = ['scm.github', 'state.markdown', 'approval.local'];
|
|
991
1026
|
const ADAPTER_VERSIONS = { 'scm.github': ASC_VERSION, 'state.markdown': ASC_VERSION };
|
|
992
1027
|
/**
|
|
@@ -1075,6 +1110,8 @@ async function runSetup(command, values, entry = 'runtime') {
|
|
|
1075
1110
|
// plan/apply๋ ๊ฐ์ ํ๋จ์ ๋๋ ์ด๋ค (C-14 ยง6). `--agent` ๋ apply์ ๋น๋ํ ํํ๋ค.
|
|
1076
1111
|
if (command === 'plan' || command === 'apply')
|
|
1077
1112
|
return runSetupLifecycle(command, values, entry);
|
|
1113
|
+
if (command === 'identity')
|
|
1114
|
+
return runSetupIdentity(values);
|
|
1078
1115
|
if (values.agent)
|
|
1079
1116
|
return runSetupLifecycle('apply', values, entry);
|
|
1080
1117
|
if (command !== undefined && command !== 'status') {
|
|
@@ -1173,6 +1210,104 @@ const nodeProcessRunner = async (command, args) => {
|
|
|
1173
1210
|
* ์ฌ๋์ด ๋ณด๋ ์ค๊ณผ agent๊ฐ ํ์ฑํ๋ JSON์ **๊ฐ์ plan**์์ ๋์จ๋ค (C-14 ๋ถ๋ณ์ โ ).
|
|
1174
1211
|
* agent ๊ฒฝ๋ก์ stdout์ JSON ๋ฌธ์ ํ๋๋ฟ์ด๊ณ , ๊ทธ ๋ฐ์ ๋ง์ stderr๋ก ๊ฐ๋ค (ยง7).
|
|
1175
1212
|
*/
|
|
1213
|
+
/**
|
|
1214
|
+
* `asc setup identity` โ ์ง๊ธ ์ด ์ฌ๋์ ์ด workspace ์ ์น์ธ ๊ถํ์๋ก ์ธ์ด๋ค (P1-F).
|
|
1215
|
+
*
|
|
1216
|
+
* ๊ฒฐ์ ์ ์ฌ๋์ด ํ๊ณ (์ด ๋ช
๋ น์ ์คํํ๋ ๊ฒ์ด ๊ทธ ๊ฒฐ์ ์ด๋ค), **ํ์ผ ํธ์ง์ ASC ๊ฐ ํ๋ค.**
|
|
1217
|
+
* ๊ทธ ์ ๊น์ง๋ identities.json ๊ณผ override.json ์ ์์ผ๋ก ๊ณ ์น๋ ๊ฒ์ด ์ ์ผํ ๊ธธ์ด์๊ณ ,
|
|
1218
|
+
* ๊ทธ ๋์ ์๋ก ๋ค๋ฅธ ํ์์ด๋ผ ํ์ชฝ๋ง ์ฑ์ ๋๊ณ ์ ์ ์ด๋ฆฌ๋์ง ๋ชจ๋ฅด๋ ์ํ๊ฐ ํํ๋ค.
|
|
1219
|
+
*
|
|
1220
|
+
* ๋น๋ฐ์ ์ฝ์ง๋ ์ฐ์ง๋ ์๋๋ค. ์ฌ๊ธฐ์ ๋ค๋ฃจ๋ ๊ฒ์ ์ด๋ฆ๊ณผ ์ฑ๋๋ฟ์ด๋ค.
|
|
1221
|
+
*/
|
|
1222
|
+
async function runSetupIdentity(values) {
|
|
1223
|
+
const resolution = await resolveRoot(process.cwd(), values.root);
|
|
1224
|
+
if (resolution.kind === 'UNRESOLVED') {
|
|
1225
|
+
console.error('Not attached yet โ run `asc init --profile <id>` first.');
|
|
1226
|
+
return 2;
|
|
1227
|
+
}
|
|
1228
|
+
const root = resolution.root;
|
|
1229
|
+
const explicit = values.actor;
|
|
1230
|
+
const candidate = explicit ?? (await detectSelf());
|
|
1231
|
+
if (!candidate) {
|
|
1232
|
+
console.error('Could not tell who you are here. Pass one: --actor local:<name>');
|
|
1233
|
+
return 2;
|
|
1234
|
+
}
|
|
1235
|
+
const actor = candidate.includes(':') ? candidate : `local:${candidate}`;
|
|
1236
|
+
const name = actor.slice(actor.indexOf(':') + 1);
|
|
1237
|
+
const roles = values.role ?? 'both';
|
|
1238
|
+
if (!['controller', 'monitor', 'both'].includes(roles)) {
|
|
1239
|
+
console.error("--role is controller|monitor|both");
|
|
1240
|
+
return 2;
|
|
1241
|
+
}
|
|
1242
|
+
const asController = roles !== 'monitor';
|
|
1243
|
+
const asMonitor = roles !== 'controller';
|
|
1244
|
+
// ์ด๋ Profile ๋ก ์ฌ๊ณ ์ ํ ์ง๋ lock ํ์ผ์์ ์ฝ๋๋ค. attachment ํ์ ์ ์ฐ๋ฉด ์ ๋๋ ์ด์ ๋
|
|
1245
|
+
// ์ด ๋ช
๋ น ์์ ์ด drift ๋ฅผ ๋ง๋ค๊ธฐ ๋๋ฌธ์ด๋ค โ ํ ๋ฒ ์คํจํ๋ฉด ๊ทธ ๋ค์๋ถํฐ๋ ์๊ธฐ๊ฐ ๋ซ์์ผ ํ
|
|
1246
|
+
// drift ๋๋ฌธ์ profile ์ ๋ชป ์ฝ์ด ์์ ๋ชป ๋ซ๋๋ค.
|
|
1247
|
+
const attachedProfile = values.profile ?? (await lockedProfileId(root));
|
|
1248
|
+
if (!attachedProfile) {
|
|
1249
|
+
console.error('๋ถ์ด ์๋ Profile ์ ์ ์ ์๋ค โ `asc setup status` ๋ฅผ ๋ณด๊ณ , ํ์ํ๋ฉด --profile ๋ก ์ง๋ชฉํ๋ผ.');
|
|
1250
|
+
return 1;
|
|
1251
|
+
}
|
|
1252
|
+
const identitiesPath = join(root, IDENTITY_FILE);
|
|
1253
|
+
const overridePath = join(root, 'override.json');
|
|
1254
|
+
const merged = withIdentity(await readJson(identitiesPath), await readJson(overridePath), {
|
|
1255
|
+
name,
|
|
1256
|
+
actor,
|
|
1257
|
+
controller: asController,
|
|
1258
|
+
monitor: asMonitor,
|
|
1259
|
+
});
|
|
1260
|
+
await writeJson(identitiesPath, merged.identities);
|
|
1261
|
+
await writeJson(overridePath, merged.override);
|
|
1262
|
+
console.log(`${name} โ ${actor}`);
|
|
1263
|
+
console.log(` identities.json ${asController ? 'approver ๋ฑ๋ก' : '๊ฑด๋๋ฆฌ์ง ์์'}`);
|
|
1264
|
+
console.log(` override.json ${asController ? 'controller.identities' : ''}${asController && asMonitor ? ' ยท ' : ''}${asMonitor ? 'monitorIdentities' : ''}`);
|
|
1265
|
+
// override ๋ lock digest ์ ๋ค์ด๊ฐ๋ค โ ๊ณ ์น ๋ค ์ฌ๊ณ ์ ํ์ง ์์ผ๋ฉด ๋ค์ ๋ช
๋ น์ด ๋ฉ์ถ๋ค.
|
|
1266
|
+
// ์ด๋ Profile ๋ก ์ฌ๊ณ ์ ํ ์ง๋ ์ง๊ธ ๋ถ์ด ์๋ ๊ฒ์ด ๋ต์ด๋ค โ ์ฌ๋์๊ฒ ๋ค์ ๋ฌป์ง ์๋๋ค.
|
|
1267
|
+
const relocked = await runProfile('resolve', { ...values, profile: attachedProfile, write: true }, root);
|
|
1268
|
+
if (relocked !== 0)
|
|
1269
|
+
return relocked;
|
|
1270
|
+
console.log('');
|
|
1271
|
+
console.log(renderSetup(await inspectSetup(root)));
|
|
1272
|
+
return 0;
|
|
1273
|
+
}
|
|
1274
|
+
/** ์ง๊ธ ๋ถ์ด ์๋ Profile id. lock ์ด ์ด๊ธ๋ ์์ด๋ ์ฝํ๋ค โ ํ์ผ์ ๊ทธ๋๋ก ๋จ์ ์๋ค. */
|
|
1275
|
+
async function lockedProfileId(root) {
|
|
1276
|
+
try {
|
|
1277
|
+
const lock = JSON.parse(await readFile(join(root, 'profile.lock'), 'utf8'));
|
|
1278
|
+
return lock.profile?.id;
|
|
1279
|
+
}
|
|
1280
|
+
catch {
|
|
1281
|
+
return undefined;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
/** gitยท๊ณ์ ์์ "์ง๊ธ ์ด ์ฌ๋"์ ์ด๋ฆ๋ง ์ฝ๋๋ค. ์๊ฒฉ ๊ฐ์ ์ฝ์ง ์๋๋ค. */
|
|
1285
|
+
async function detectSelf() {
|
|
1286
|
+
const fromGit = await execText('git', ['config', 'user.name']);
|
|
1287
|
+
if (fromGit)
|
|
1288
|
+
return fromGit;
|
|
1289
|
+
const user = userInfo().username;
|
|
1290
|
+
return user || null;
|
|
1291
|
+
}
|
|
1292
|
+
async function execText(command, args) {
|
|
1293
|
+
try {
|
|
1294
|
+
const { stdout } = await execFileAsync(command, args);
|
|
1295
|
+
return stdout.trim() || null;
|
|
1296
|
+
}
|
|
1297
|
+
catch {
|
|
1298
|
+
return null;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
async function readJson(path) {
|
|
1302
|
+
try {
|
|
1303
|
+
const parsed = JSON.parse(await readFile(path, 'utf8'));
|
|
1304
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
1305
|
+
}
|
|
1306
|
+
catch {
|
|
1307
|
+
return {};
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
const writeJson = (path, value) => writeFile(path, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
1176
1311
|
async function runSetupLifecycle(command, values, entry) {
|
|
1177
1312
|
const asJson = Boolean(values.json) || Boolean(values.agent);
|
|
1178
1313
|
const plan = computeSetupPlan(await detectSetupState(values, entry));
|
|
@@ -1399,9 +1534,18 @@ async function runProfile(command, values, root) {
|
|
|
1399
1534
|
...(values.preset ? { presetId: values.preset } : {}),
|
|
1400
1535
|
overridePath: join(root, 'override.json'),
|
|
1401
1536
|
});
|
|
1402
|
-
// ๋ฌด์์ด ์ค์ ๋ก ์ ๊ณต๋๋์ง๋ ๋ถ์ด ์๋ Adapter๊ฐ ์ ํ๋ค
|
|
1403
|
-
|
|
1404
|
-
|
|
1537
|
+
// ๋ฌด์์ด ์ค์ ๋ก ์ ๊ณต๋๋์ง๋ ๋ถ์ด ์๋ Adapter๊ฐ ์ ํ๋ค โ ์์๊ฐ ์๋๋ผ ์ค์ธก์ด๋ค (A5).
|
|
1538
|
+
// discoverโprobe ๋ฅผ ์ค์ ๋ก ๋๋ฆฐ๋ค: glab ๋ก๊ทธ์ธ ๊ฐ์ ์ํ ๋ณํ๊ฐ resolve ์ฌ์คํ์ผ๋ก
|
|
1539
|
+
// ๋ฐ์๋๋ค (re-probe ์๋จ์ด ๋ฐ๋ก ํ์ ์๋ค). ์ค์ธก ์คํจ๋ ๊ทธ ๊ฐ๋๊ฐ ๋น ์ง ๋ฟ์ด๋ค.
|
|
1540
|
+
const composed = await composeBindings({ context: { projectRoot: root, env: process.env } }).catch(() => ({ bindings: [] }));
|
|
1541
|
+
for (const binding of composed.bindings) {
|
|
1542
|
+
console.log(`Binding: ${binding.adapterId}/${binding.resource} โ ${binding.state}${binding.detail ? ` (${binding.detail})` : ''}`);
|
|
1543
|
+
}
|
|
1544
|
+
// lock ์ capability ํ๊ธฐ๋ ์์ง ์์๋ค โ ์ค์ธก์ digest ์ฌ๋ฃ๋ก ์ฐ๋ฉด glab ๋ก๊ทธ์ธ ์ฌ๋ถ์
|
|
1545
|
+
// ๋ฐ๋ผ lock ์ด ํ๋ค๋ฆฐ๋ค. ์ค์ธก์ lock ์ฒด๊ณ์ ๊ดํต์ํค๋ ๊ฒ์ P1 ๋ก ๋๊ธฐ๊ณ (์ฌ์ค๊ณ ์์ญ),
|
|
1546
|
+
// ์ฌ๊ธฐ์๋ probe ์ค์ธก์ ์ฌ๋์๊ฒ ๋ณด์ด๋ ๊ฒ๊น์ง ํ๋ค. ์ค์ฌ์ฉ read ๊ฒฝ๋ก(proceed)๋
|
|
1547
|
+
// buildWorkIngress ๊ฐ ์ด๋ฏธ composeBindings ์ค์ธก์ผ๋ก ์กฐ๋ฆฝํ๋ค.
|
|
1548
|
+
const result = resolveRuntime(layers, CAPABILITIES, ASC_VERSION);
|
|
1405
1549
|
if (!result.ok) {
|
|
1406
1550
|
console.error('resolve failed:');
|
|
1407
1551
|
for (const failure of result.failures) {
|
|
@@ -1414,7 +1558,7 @@ async function runProfile(command, values, root) {
|
|
|
1414
1558
|
const lock = buildLock({
|
|
1415
1559
|
runtime,
|
|
1416
1560
|
ascVersion: ASC_VERSION,
|
|
1417
|
-
adapters:
|
|
1561
|
+
adapters: ADAPTER_VERSIONS,
|
|
1418
1562
|
generatedAt,
|
|
1419
1563
|
});
|
|
1420
1564
|
console.log(`Layers: ${runtime.resolved.policy.layers.join(' โ ')}`);
|
|
@@ -1713,11 +1857,18 @@ async function runProceed(values, store, root, resolved) {
|
|
|
1713
1857
|
canonicalSources: (resolved?.canonicalSources ?? []).map((sourceId) => ({ sourceId })),
|
|
1714
1858
|
...(resolved?.ownership ? { ownership: resolved.ownership } : {}),
|
|
1715
1859
|
});
|
|
1860
|
+
const workRef = values.work ?? undefined;
|
|
1861
|
+
const ingress = workRef ? await buildWorkIngress(store, root, sessions, resolved) : undefined;
|
|
1862
|
+
if (workRef && !ingress) {
|
|
1863
|
+
console.error(`์์
ํญ๋ชฉ '${workRef}' ์ ์ฝ์ ํต๋ก๊ฐ ์๋ค โ Profile bindings ์ ์์
ํญ๋ชฉ provider ๋ฅผ ์ ์ธํ๋ผ.`);
|
|
1864
|
+
return 2;
|
|
1865
|
+
}
|
|
1716
1866
|
const operator = new Operator({
|
|
1717
1867
|
store,
|
|
1718
1868
|
sessions,
|
|
1719
1869
|
// ๋งํ node๋ง ๋ณด๊ณ ํ๋จํ๋ค โ checkpoint๋ฅผ ๋ฐํํ๋ค๋ ์ด์ ๋ก ๋ฉ์ถ์ง ์๋๋ค (C-13 ยง3.1)
|
|
1720
1870
|
escalations: escalationLedger(store),
|
|
1871
|
+
...(ingress ? { ingress } : {}),
|
|
1721
1872
|
// main()์ checkBootstrap๊ณผ ๊ฐ์ ์์ฒ(bootstrapGuard)์ด๋ค โ ์ค๋ณต ํ๋จ์ด ์๋๋ผ ๊ฐ์ ๋ฌธ
|
|
1722
1873
|
guard: async () => {
|
|
1723
1874
|
const outcome = await checkBootstrap(root);
|
|
@@ -1727,7 +1878,10 @@ async function runProceed(values, store, root, resolved) {
|
|
|
1727
1878
|
const outcome = await operator.proceed({
|
|
1728
1879
|
...(values.session ? { sessionId: values.session } : {}),
|
|
1729
1880
|
...(values.goal ? { goal: values.goal } : {}),
|
|
1881
|
+
...(workRef ? { workRef } : {}),
|
|
1730
1882
|
});
|
|
1883
|
+
// ๋๊ตฌ ์์(JAM MCP ์๋ฒ ๋ฑ)์ ์ฌ๊ธฐ์ ๋ซ๋๋ค โ ์ ๋ซ์ผ๋ฉด ์ถ๋ ฅ๊น์ง ๋๋ด๊ณ ๋ ์ข
๋ฃํ์ง ๋ชปํ๋ค.
|
|
1884
|
+
await closeToolClients();
|
|
1731
1885
|
if (values.json) {
|
|
1732
1886
|
console.log(JSON.stringify(outcome, null, 2));
|
|
1733
1887
|
return outcome.kind.startsWith('BLOCKED') || outcome.kind === 'FAILED' ? 1 : 0;
|
|
@@ -1781,7 +1935,39 @@ async function runProceed(values, store, root, resolved) {
|
|
|
1781
1935
|
console.log(` ${c.id} ${c.status.padEnd(7)} ${c.wouldDo.padEnd(8)} ${c.goal}`);
|
|
1782
1936
|
}
|
|
1783
1937
|
return 1;
|
|
1938
|
+
case 'WORK_STATE': {
|
|
1939
|
+
const shown = outcome.result.leaning
|
|
1940
|
+
? `${outcome.result.state} (${outcome.result.leaning})`
|
|
1941
|
+
: outcome.result.state;
|
|
1942
|
+
console.log(`${outcome.workRef}: ${shown}`);
|
|
1943
|
+
for (const line of outcome.result.evidence)
|
|
1944
|
+
console.log(` ๊ทผ๊ฑฐ ${line}`);
|
|
1945
|
+
for (const line of outcome.result.limitations)
|
|
1946
|
+
console.log(` ํ๊ณ ${line}`);
|
|
1947
|
+
for (const line of outcome.result.missing)
|
|
1948
|
+
console.log(` ๋ฏธํ์ธ ${line}`);
|
|
1949
|
+
console.log(`\n๋ค์ ํ๋: ${outcome.nextAction}`);
|
|
1950
|
+
return outcome.result.state === 'UNDECIDABLE' ? 1 : 0;
|
|
1951
|
+
}
|
|
1784
1952
|
case 'PROPOSE_CONTRACT':
|
|
1953
|
+
if (outcome.plan) {
|
|
1954
|
+
console.log(`${outcome.plan.status}${outcome.full?.id ? ` โ ${outcome.full.id}` : ''}`);
|
|
1955
|
+
for (const fact of outcome.plan.facts)
|
|
1956
|
+
console.log(` fact ${fact.field} (${fact.source})`);
|
|
1957
|
+
for (const proposal of outcome.plan.proposals) {
|
|
1958
|
+
console.log(` proposal ${proposal.field} โ ${proposal.reason ?? proposal.source}`);
|
|
1959
|
+
}
|
|
1960
|
+
for (const item of outcome.plan.invalid)
|
|
1961
|
+
console.log(` invalid ${item.field}: ${item.detail}`);
|
|
1962
|
+
for (const item of outcome.plan.unresolved) {
|
|
1963
|
+
console.log(` decide ${item.field} [${item.reason}]: ${item.detail}`);
|
|
1964
|
+
}
|
|
1965
|
+
if (outcome.forController) {
|
|
1966
|
+
console.log(`\n๊ณ์ฝ์ ์ฑ๋ฆฝํ๋ค. ๋ฐ๊ธ์ Controller ์ ๊ฒ์ด๋ค โ ${outcome.plan.issuance.detail}:`);
|
|
1967
|
+
console.log(` ${shorthandCommand(outcome.forController.slice(1))}`);
|
|
1968
|
+
}
|
|
1969
|
+
return outcome.plan.status === 'READY_TO_ISSUE' ? 0 : 1;
|
|
1970
|
+
}
|
|
1785
1971
|
console.log('No runnable session. If a new contract is needed, the Controller issues it:');
|
|
1786
1972
|
console.log(` asc session issue S-<date>-<n> --role ${outcome.draft.role} --goal "${outcome.draft.goal || '<goal>'}"`);
|
|
1787
1973
|
return 1;
|
|
@@ -1806,6 +1992,203 @@ async function runProceed(values, store, root, resolved) {
|
|
|
1806
1992
|
return 1;
|
|
1807
1993
|
}
|
|
1808
1994
|
}
|
|
1995
|
+
/**
|
|
1996
|
+
* ์ด๋ฏธ ์ด ์ธ์
id. **ํ์๋ผ ๋ณด๊ด๋ ๊ฒ๊น์ง ์ผ๋ค** โ ๊ทธ ๋ฒํธ๋ฅผ ๋ค์ ์ฐ๋ฉด ์์ ๊ณ์ฝ ๊ธฐ๋ก
|
|
1997
|
+
* ์์ ๋ค๋ฅธ ๊ณ์ฝ์ด ์๋๋ค. ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๊ธฐ๋ก ํ๋๋ฅผ ์์๋ค.
|
|
1998
|
+
*/
|
|
1999
|
+
async function usedSessionIds(store, root) {
|
|
2000
|
+
const active = (await store.list('session')).map((session) => session.id);
|
|
2001
|
+
let archived = [];
|
|
2002
|
+
try {
|
|
2003
|
+
archived = (await readdir(join(root, 'sessions', 'archive')))
|
|
2004
|
+
.filter((name) => name.endsWith('.md'))
|
|
2005
|
+
.map((name) => name.slice(0, -3));
|
|
2006
|
+
}
|
|
2007
|
+
catch {
|
|
2008
|
+
archived = [];
|
|
2009
|
+
}
|
|
2010
|
+
return [...new Set([...active, ...archived])];
|
|
2011
|
+
}
|
|
2012
|
+
/**
|
|
2013
|
+
* ์ ์ฅ์์ ์ต์์ ์๋ฆฌ์ ๊ทธ ์๋ `src`. ๋ถ๋ฅ ์ด๋ฆ์ด ์ด๋ ๋ชจ๋์ ๋ง๋์ง ์ฌ๋ ์ฌ๋ฃ๋ค โ
|
|
2014
|
+
* ๋ชฉ๋ก์ผ ๋ฟ์ด๊ณ , ์ด๊ฒ์ด ์ฐ๊ธฐ ๋ฒ์๊ฐ ๋์ง๋ ์๋๋ค (derive ๊ฐ ์ต์์๋ ๋ฒ์๋ก ์ฐ์ง ์๋๋ค).
|
|
2015
|
+
*/
|
|
2016
|
+
async function topLevelModules(projectRoot) {
|
|
2017
|
+
try {
|
|
2018
|
+
const entries = await readdir(projectRoot, { withFileTypes: true });
|
|
2019
|
+
return entries
|
|
2020
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules')
|
|
2021
|
+
.flatMap((entry) => [entry.name, `${entry.name}/src`]);
|
|
2022
|
+
}
|
|
2023
|
+
catch {
|
|
2024
|
+
return [];
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
/** ์ ํยท์์กด์ผ๋ก ๋ณผ ํ๋ณด. ๋งํฌ๊ฐ ๋จผ์ ๊ณ , ๋ณธ๋ฌธ์ด ๋งํ ํค๊ฐ ๊ทธ๋ค์์ด๋ค. ์ํ์ 5. */
|
|
2028
|
+
const DEPENDENCY_CAP = 5;
|
|
2029
|
+
function dependencyCandidates(workItem) {
|
|
2030
|
+
if (!workItem)
|
|
2031
|
+
return [];
|
|
2032
|
+
// ๋ณธ๋ฌธ์ด "BLOCKED BY: KEY-1" ์ฒ๋ผ ๋งํ ๊ฒ์ ๋งํฌ๊ฐ ์์ด๋ ์์กด์ด๋ค โ ๋งํฌ๊ฐ ์๋ค๋
|
|
2033
|
+
// ์ฌ์ค์ด ์์กด์ด ์๋ค๋ ๋ป์ ์๋๋ค.
|
|
2034
|
+
const fromBody = new Set();
|
|
2035
|
+
const project = workItem.reference.split('-')[0];
|
|
2036
|
+
if (project) {
|
|
2037
|
+
const pattern = new RegExp(`(?:blocked\\s*by|์ ํ|์์กด)[^\\n]*?(${project}-\\d+)`, 'gi');
|
|
2038
|
+
for (const [, key] of `${workItem.body ?? ''}`.matchAll(pattern))
|
|
2039
|
+
if (key)
|
|
2040
|
+
fromBody.add(key);
|
|
2041
|
+
}
|
|
2042
|
+
// ๋ถ๋ชจยทํ์ ์์
์ ํฌํจ ๊ด๊ณ์ด์ง ์ ํ์ด ์๋๋ค โ ๊ทธ๊ฒ๊น์ง ์ธ๋ฉด ๊ฑฐ์ ๋ชจ๋ ์์
์ด ๋งํ๋ค.
|
|
2043
|
+
const ordered = [...(workItem.blockedBy ?? []), ...fromBody].filter((key) => key !== workItem.reference);
|
|
2044
|
+
return [...new Set(ordered)].slice(0, DEPENDENCY_CAP);
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* ์์
ํญ๋ชฉ ํ๋๋ฅผ ์กฐ์ฌํด ๊ณ์ฝ๊น์ง ์๋ ํต๋ก (P0-D).
|
|
2048
|
+
*
|
|
2049
|
+
* ์ฌ๊ธฐ์ ํ์ ํ์ง ์๋๋ค. ๋ชจ์ผ๊ณ (gatherยทobserveRepo), ๋์ถํ๊ณ (derive), **๊ธฐ์กด ํ์ ๊ธฐ์
|
|
2050
|
+
* ๋๊ธด๋ค**(plan = planSessionContract, issue = SessionRuntime). ๋ฒ์ยท์ฑ
์ยท๋ฐ๊ธ ๊ถํ์
|
|
2051
|
+
* ๊ทธ๊ฒ๋ค์ด ๋ตํ๋ ๊ฒ์ ๊ทธ๋๋ก ์ด๋ค.
|
|
2052
|
+
*
|
|
2053
|
+
* buildMonitorEngine ์ ๊ฑฐ์น์ง ์๋ ์ด์ : ๊ทธ ํจ์๋ GitHub ํ ํฐ์ด ์์ผ๋ฉด ๋ฉ์ถ๋ค. ๊ฐ์์๋
|
|
2054
|
+
* ๋ง๋ ๋ฌธ์ด์ง๋ง, GitLabยทJAM ํ๋ก์ ํธ์์ ์ ์ฅ์ ์กฐ์ฌ๊น์ง ๋ง์ ๋ฒ๋ฆฐ๋ค โ ๊ทธ๊ฒ์ด "์๊ฒฉ์ด
|
|
2055
|
+
* ๋งํ์ผ๋ ์ ์ฅ์๋ ๋ชป ๋ณธ๋ค"๋ ์๋ชป๋ ๊ฒฐ๋ก ์ ๋ง๋ ๊ตฌ์กฐ๋ค.
|
|
2056
|
+
*/
|
|
2057
|
+
async function buildWorkIngress(store, root, runtime, resolved) {
|
|
2058
|
+
const { root: projectRoot } = await discoverProjectRoot(process.cwd());
|
|
2059
|
+
// JAM ์ ์์ง `jam` ๋ฐ์ด๋๋ฆฌ๋ฅผ ๊น์ง ์๋ ์ค์น๊ฐ ๊ธฐ๋ณธ์ด๋ค โ ๊ทธ ๊ฒฝ์ฐ launcher ๋ฅผ ํตํด ๋ถ๋ฅธ๋ค.
|
|
2060
|
+
const jamCommand = process.env.ASC_JAM_PATH ? undefined : { command: 'npx', args: ['--yes', '@jam-mcp/launcher'] };
|
|
2061
|
+
const adapters = [
|
|
2062
|
+
new GitHubAdapter(),
|
|
2063
|
+
new GitLabAdapter(),
|
|
2064
|
+
new JamAdapter(jamCommand ?? {}),
|
|
2065
|
+
];
|
|
2066
|
+
const declared = resolved?.layers.profile.bindings ?? [];
|
|
2067
|
+
const plan = await composeBindings({
|
|
2068
|
+
context: { projectRoot, env: process.env },
|
|
2069
|
+
adapters,
|
|
2070
|
+
roles: declared.map((b) => ({ adapterId: b.adapter, resource: b.resource, role: b.role })),
|
|
2071
|
+
});
|
|
2072
|
+
// ์ ์ธ์ด ์์ผ๋ฉด ๋ฐ๊ฒฌ๋ ์ฌ์ค๋ก ์ ์ํ๋ค (P1-G). ์ ์ฅํ์ง ์๊ณ , ๊ฐ๋ฆฌ๋ฉด ๊ณ ๋ฅด์ง ์๋๋ค.
|
|
2073
|
+
const proposed = declared.length === 0 ? proposeBindings(plan) : undefined;
|
|
2074
|
+
if (proposed) {
|
|
2075
|
+
for (const reason of proposed.reasons)
|
|
2076
|
+
console.error(` ์ ์ ${reason}`);
|
|
2077
|
+
for (const conflict of proposed.conflicts)
|
|
2078
|
+
console.error(` ๋ณด๋ฅ ${conflict}`);
|
|
2079
|
+
}
|
|
2080
|
+
const ports = await buildRuntimePorts({
|
|
2081
|
+
plan,
|
|
2082
|
+
// ์ ์์ **๋งํ๋ ๊ฒ**์ด์ง ์ ํ๋ ๊ฒ์ด ์๋๋ค. ์ญํ ์ ๋ฐ์ ๋ฃ์ผ๋ฉด ์ ์ธ๊ณผ ๊ตฌ๋ถ๋์ง ์๊ณ ,
|
|
2083
|
+
// capability ํด์์ ํ๋ณด๊ฐ ์ ์ผํ ๋ ์ด๋ฏธ ์ค์ค๋ก ํ๋ฆฐ๋ค.
|
|
2084
|
+
roles: rolesFor(plan, declared),
|
|
2085
|
+
perPage: 30,
|
|
2086
|
+
jam: { command: jamCommand?.command ?? 'jam', args: [...(jamCommand?.args ?? []), 'serve'], cwd: projectRoot },
|
|
2087
|
+
endpointFor: (binding) => endpointOf(adapters, binding),
|
|
2088
|
+
});
|
|
2089
|
+
const work = ports.resourceContext;
|
|
2090
|
+
if (!work)
|
|
2091
|
+
return undefined;
|
|
2092
|
+
// ์ ์ฅ์๋ ์๊ฒฉ provider ์ ๋ฌด๊ดํ๊ฒ ๋ณธ๋ค. ์ด ํ ์ค์ด P0-E ์ ์์ ์ด๋ค.
|
|
2093
|
+
const repo = new LocalRepoAdapter({ cwd: projectRoot });
|
|
2094
|
+
const canonicalSource = resolved?.layers.profile.canonical.sources[0];
|
|
2095
|
+
const canonicalRef = canonicalSource?.ref;
|
|
2096
|
+
// remote ๋ฅผ ๋ฒ๋ฆฌ๋ฉด ๋ก์ปฌ ๋ธ๋์น๋ฅผ ์ ๋ณธ์ฒ๋ผ ์ฝ๋๋ค โ ์ค์ ์คํ์ ๊ฒฝ๋ก์๋ค.
|
|
2097
|
+
const canonicalRemote = canonicalSource?.remote;
|
|
2098
|
+
const canonicalPaths = resolved?.layers.profile.canonical.sources.flatMap((source) => source.paths) ?? [];
|
|
2099
|
+
const changeContext = ports.changeContext;
|
|
2100
|
+
return {
|
|
2101
|
+
gather: async (workRef) => {
|
|
2102
|
+
const workItem = await work.getResource(workRef).catch(() => undefined);
|
|
2103
|
+
const comments = await work
|
|
2104
|
+
.getComments(workRef, { limit: 20 })
|
|
2105
|
+
.then((list) => list)
|
|
2106
|
+
.catch(() => 'UNAVAILABLE');
|
|
2107
|
+
const change = changeContext
|
|
2108
|
+
? await changeContext
|
|
2109
|
+
.getChange(workRef)
|
|
2110
|
+
.then((summary) => summary)
|
|
2111
|
+
.catch(() => 'UNAVAILABLE')
|
|
2112
|
+
: 'UNAVAILABLE';
|
|
2113
|
+
// ์ ํ ์์
์ด ์ด๋ ค ์๋์ง๋ **์กฐํํด์ผ** ์๋ค. ํค๋ง ๋๊ธฐ๋ฉด ํ์ ์ด ๋ "๋ชจ๋ฅธ๋ค"๊ฐ ๋๊ณ ,
|
|
2114
|
+
// ๊ทธ๋ฌ๋ฉด ๋งํ ์์
์ด ์ฐฉ์ ๊ฐ๋ฅ์ผ๋ก ๋ณด์ธ๋ค. adapter ๊ฐ ๋ง๋ ๊ฒ์ ์์ ์ค์ด ์ฃผ๋ฏ๋ก
|
|
2115
|
+
// ์ํ์ ๊ฑธ๋ ค๋ blocker ๊ฐ ๋จผ์ ํ์ธ๋๋ค.
|
|
2116
|
+
const candidates = dependencyCandidates(workItem);
|
|
2117
|
+
const dependencies = await Promise.all(candidates.map(async (reference) => {
|
|
2118
|
+
const item = await work.getResource(reference).catch(() => undefined);
|
|
2119
|
+
const done = item && !item.missing ? statusIndicatesDone(item.state) : undefined;
|
|
2120
|
+
return {
|
|
2121
|
+
reference,
|
|
2122
|
+
...(item?.state ? { state: item.state } : {}),
|
|
2123
|
+
...(done === undefined ? {} : { open: !done }),
|
|
2124
|
+
};
|
|
2125
|
+
}));
|
|
2126
|
+
return {
|
|
2127
|
+
...(workItem ? { workItem } : {}),
|
|
2128
|
+
...(workItem ? { trackerDone: statusIndicatesDone(workItem.state) } : {}),
|
|
2129
|
+
comments,
|
|
2130
|
+
change,
|
|
2131
|
+
dependencies,
|
|
2132
|
+
};
|
|
2133
|
+
},
|
|
2134
|
+
observeRepo: async (query) => {
|
|
2135
|
+
// ์กฐํํ ๊ฒฝ๋ก๋ **์์
ํญ๋ชฉ์ด ์ง๋ชฉํ ๊ฒ**์ด ๋จผ์ ๋ค. ๊ทธ๊ฒ์ ํ์ธํด์ผ ์ข์ ๋ฒ์๋ฅผ
|
|
2136
|
+
// ๋ง๋ค ์ ์๊ณ , ํ์ธํ์ง ์์ผ๋ฉด ๋์ ๋ฒ์๋ฐ์ ๋จ์ง ์๋๋ค. ์ ์ฅ์์ ์ต์์ ์๋ฆฌ๋
|
|
2137
|
+
// ํจ๊ป ํ์ธํ๋ค โ ๋ถ๋ฅ ์ด๋ฆ์ด ์ด๋ ๋ชจ๋ ํ๋์๋ง ๋ง๋์ง ์ฌ๋ ค๋ฉด ๊ทธ ๋ชฉ๋ก์ด ์์ด์ผ ํ๋ค.
|
|
2138
|
+
const modules = await topLevelModules(projectRoot);
|
|
2139
|
+
const paths = [...new Set([...(query.paths ?? []), ...canonicalPaths])];
|
|
2140
|
+
return repo.observe({
|
|
2141
|
+
refHint: query.refHint,
|
|
2142
|
+
...(canonicalRef ? { canonicalRef } : {}),
|
|
2143
|
+
...(canonicalRemote ? { remote: canonicalRemote } : {}),
|
|
2144
|
+
...(paths.length > 0 ? { paths } : {}),
|
|
2145
|
+
...(modules.length > 0 ? { modulePaths: modules } : {}),
|
|
2146
|
+
});
|
|
2147
|
+
},
|
|
2148
|
+
usedIds: () => usedSessionIds(store, root),
|
|
2149
|
+
derive: (input) => deriveSessionContractDraft({
|
|
2150
|
+
existingIds: input.existingIds,
|
|
2151
|
+
intent: { workRef: input.workRef, ...(input.goal ? { goal: input.goal } : {}) },
|
|
2152
|
+
workItem: input.workItem,
|
|
2153
|
+
workState: input.workState,
|
|
2154
|
+
repo: input.repo,
|
|
2155
|
+
// ์ํ์ด์ง ์ถ์ฒ๊ฐ ์๋๋ค โ ๋์ถํ ํ๋ณด๊ฐ ์ด ๋ฐ์ผ๋ก ๋๊ฐ์ง ์๋์ง ์ฌ๋ ๋ฐ๋ง ์ด๋ค.
|
|
2156
|
+
maxScopes: resolved?.resolved.policy.roleScopes.implementer ?? [],
|
|
2157
|
+
...(resolved?.ownership ? { ownership: resolved.ownership } : {}),
|
|
2158
|
+
today: new Date().toISOString().slice(0, 10).replace(/-/g, ''),
|
|
2159
|
+
}),
|
|
2160
|
+
plan: async (draft) => planSessionContract({
|
|
2161
|
+
draft,
|
|
2162
|
+
...(resolved?.resolved.policy ? { policy: resolved.resolved.policy } : {}),
|
|
2163
|
+
...(resolved?.ownership ? { ownership: resolved.ownership } : {}),
|
|
2164
|
+
existingIds: await usedSessionIds(store, root),
|
|
2165
|
+
}),
|
|
2166
|
+
issue: async (draft) => {
|
|
2167
|
+
// ๋ฐ๊ธ ๊ฒฝ๋ก๋ ํ๋๋ฟ์ด๋ค โ `asc session issue` ์ ๊ฐ์ SessionRuntime.issue ๋ฅผ ๋ถ๋ฅธ๋ค.
|
|
2168
|
+
const issued = await runtime.issue({
|
|
2169
|
+
id: draft.id,
|
|
2170
|
+
role: SessionRole.parse(draft.role ?? 'implementer'),
|
|
2171
|
+
goal: draft.goal ?? '',
|
|
2172
|
+
...(draft.criteria ? { doneCriteria: [...draft.criteria] } : {}),
|
|
2173
|
+
...(draft.boundary ? { writeBoundary: [...draft.boundary] } : {}),
|
|
2174
|
+
...(draft.owner ? { owner: draft.owner } : {}),
|
|
2175
|
+
});
|
|
2176
|
+
if (!issued.ok) {
|
|
2177
|
+
return { ok: false, detail: issued.failures.map((f) => `${f.kind}: ${f.detail}`).join('; ') };
|
|
2178
|
+
}
|
|
2179
|
+
await auditLedger(store).delegate({
|
|
2180
|
+
childSessionId: issued.session.id,
|
|
2181
|
+
role: issued.session.role,
|
|
2182
|
+
goal: issued.session.goal,
|
|
2183
|
+
scope: issued.session.writeBoundary,
|
|
2184
|
+
doneCriteria: issued.session.doneCriteria,
|
|
2185
|
+
issuedBy: issued.session.owner ?? '(์์ ๋ฒ์ ๋ด ์๋ ๋ฐ๊ธ)',
|
|
2186
|
+
issuedAt: new Date().toISOString(),
|
|
2187
|
+
});
|
|
2188
|
+
return { ok: true, sessionId: issued.session.id };
|
|
2189
|
+
},
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
1809
2192
|
/** ์ธ์
lifecycle. ๊ณ์ฝ์ ๋ฐ๊ธํ๊ณ , ์ค๋จยท์ฌ๊ฐํ๊ณ , Handoff๊น์ง ๋จ๊ธด๋ค (OM ยง6.2). */
|
|
1810
2193
|
/**
|
|
1811
2194
|
* ์ด ์ธ์
์ด ๊ฑธ๋ฆฐ ๊ฒฐ์ ๋ง๋ค ์ค์ ๊ฒฐ์ ๊ถ์. ์ธ์
๊ณ์ฝ์ด ๋จผ์ ๊ณ , ์์ผ๋ฉด Profile ์ง๋์์ ํผ๋ค.
|
|
@@ -1840,6 +2223,94 @@ function parseAuthority(pairs) {
|
|
|
1840
2223
|
}
|
|
1841
2224
|
return { ok: true, map };
|
|
1842
2225
|
}
|
|
2226
|
+
/**
|
|
2227
|
+
* ์ด์์ ์ฌ ๋ณธ๋ค. **์๋ฌด๊ฒ๋ ๋ฐ๊ธํ์ง ์๋๋ค** (C-14 ยง6์ plan/apply ๋ถ๋ฆฌ์ ๊ฐ์ ์์ธ).
|
|
2228
|
+
*
|
|
2229
|
+
* agent๊ฐ ์ฌ์ฉ์ ์์ฒญยทwork itemยทProfileยท์ ์ฅ์๋ฅผ ์ฝ์ด ๊ณ์ฝ ์ด์์ ๋ง๋ค๊ณ , ์ฌ๊ธฐ์ ๊ทธ๊ฒ์ด
|
|
2230
|
+
* ๊ตฌ์กฐยท๊ฒฝ๊ณ๋ก ์ฑ๋ฆฝํ๋์ง ํ์ธํ๋ค. ํ์ ์ ์
๋ฟ์ด๋ค โ ๋ฐ๊ธํด๋ ๋๋ค / ์ฌ๋์ด ์ ํ ๊ฒ์ด
|
|
2231
|
+
* ๋จ์๋ค / ์ด ์ด์์ผ๋ก๋ ๊ณ์ฝ์ด ์ ๋๋ค.
|
|
2232
|
+
*/
|
|
2233
|
+
async function runSessionPlan(values, store, resolved) {
|
|
2234
|
+
const authority = parseAuthority(values.authority);
|
|
2235
|
+
if (!authority.ok) {
|
|
2236
|
+
console.error(authority.detail);
|
|
2237
|
+
return 2;
|
|
2238
|
+
}
|
|
2239
|
+
// ์ถ์ฒ๋ `<field>=<status>[:<source>]` ๋ก ๋ฐ๋๋ค โ ์ด์์ ๋ง๋ ์ชฝ์ด ๋ฌด์์ ํ์ธํ๊ณ
|
|
2240
|
+
// ๋ฌด์์ ์ ์ํ๋์ง ์ค์ค๋ก ์ ๊ฒ ํ๋ค. ์ ์ง ์์ผ๋ฉด ์ ์์ผ๋ก ์
ํ๋ค(์ฌ์ค๋ก ์ฌ๋ฆฌ์ง ์๋๋ค).
|
|
2241
|
+
const provenance = [];
|
|
2242
|
+
for (const raw of values.provenance ?? []) {
|
|
2243
|
+
const [field, rest] = raw.split('=', 2);
|
|
2244
|
+
const [status, source] = (rest ?? '').split(':', 2);
|
|
2245
|
+
const parsed = DraftProvenance.safeParse({
|
|
2246
|
+
field,
|
|
2247
|
+
status,
|
|
2248
|
+
source: source ?? 'agent_proposal',
|
|
2249
|
+
...(values.why ? { reason: values.why[0] } : {}),
|
|
2250
|
+
});
|
|
2251
|
+
if (!parsed.success) {
|
|
2252
|
+
console.error(`--provenance ๋ <field>=<FACT|PROPOSAL|DECISION_REQUIRED>[:<source>] ํ์์ด๋ค: '${raw}'`);
|
|
2253
|
+
return 2;
|
|
2254
|
+
}
|
|
2255
|
+
provenance.push(parsed.data);
|
|
2256
|
+
}
|
|
2257
|
+
const draft = {
|
|
2258
|
+
...(values.id ? { id: values.id } : {}),
|
|
2259
|
+
...(values.role ? { role: values.role } : {}),
|
|
2260
|
+
...(values.goal ? { goal: values.goal } : {}),
|
|
2261
|
+
...(values.boundary ? { boundary: values.boundary } : {}),
|
|
2262
|
+
...(values.criteria ? { criteria: values.criteria } : {}),
|
|
2263
|
+
...(values.owner ? { owner: values.owner } : {}),
|
|
2264
|
+
...(values.domain ? { decisionDomains: values.domain } : {}),
|
|
2265
|
+
...(Object.keys(authority.map).length > 0 ? { decisionAuthority: authority.map } : {}),
|
|
2266
|
+
...(provenance.length > 0 ? { provenance } : {}),
|
|
2267
|
+
};
|
|
2268
|
+
const plan = planSessionContract({
|
|
2269
|
+
draft,
|
|
2270
|
+
...(resolved?.resolved.policy ? { policy: resolved.resolved.policy } : {}),
|
|
2271
|
+
...(resolved?.ownership ? { ownership: resolved.ownership } : {}),
|
|
2272
|
+
existingIds: (await store.list('session')).map((session) => session.id),
|
|
2273
|
+
});
|
|
2274
|
+
// ํต๊ณผํ์ ๋๋ง ์คํ ๊ฐ๋ฅํ ๋ช
๋ น์ ์ค๋ค. ํต๊ณผํ์ง ์์ ์ด์์ ๋ช
๋ น์ ํจ๊ป ์ฃผ๋ฉด
|
|
2275
|
+
// agent๋ ๊ทธ๊ฒ์ "๊ณ ์น๊ณ ๋์ ์ธ ๊ฒ"์ด ์๋๋ผ "์ง๊ธ ์ธ ๊ฒ"์ผ๋ก ์ฝ๋๋ค.
|
|
2276
|
+
//
|
|
2277
|
+
// ๊ทธ๋ฆฌ๊ณ **์์ฑ๋ ๊ณ์ฝ์ด๋ผ๊ณ ํด์ ๋ฐ๊ธํด๋ ๋๋ ๊ฒ์ ์๋๋ค** (OM ยง450). ์์์ด ์์ผ๋ฉด
|
|
2278
|
+
// ๋ช
๋ น์ `forController` ๋ก ๊ฐ๋ค โ actions์ ๋ฃ์ผ๋ฉด "portable์ ์คํํ๋ผ"๋ ์ง์๋ฅผ ๋ฐ๋ฅด๋
|
|
2279
|
+
// agent๊ฐ ์ฌ๋์ ๊ถํ์ ๋์ ์ฐ๊ฒ ๋๋ค.
|
|
2280
|
+
const issuable = plan.status === 'READY_TO_ISSUE';
|
|
2281
|
+
const command = {
|
|
2282
|
+
display: shorthandCommand(issueArgs(draft)),
|
|
2283
|
+
portable: shorthandCommand([...issueArgs(draft), '--json']),
|
|
2284
|
+
};
|
|
2285
|
+
const actions = issuable && plan.issuance.authority === 'delegated' ? [{ type: 'issue_session', ...command }] : [];
|
|
2286
|
+
const forController = issuable && plan.issuance.authority === 'controller' ? command : undefined;
|
|
2287
|
+
if (values.json || values.agent) {
|
|
2288
|
+
console.log(JSON.stringify({ ...plan, nextActions: actions.map((action) => action.portable), actions, ...(forController ? { forController } : {}) }, null, 2));
|
|
2289
|
+
}
|
|
2290
|
+
else {
|
|
2291
|
+
console.log(`${plan.status}${plan.draft.id ? ` โ ${plan.draft.id}` : ''}`);
|
|
2292
|
+
for (const fact of plan.facts)
|
|
2293
|
+
console.log(` fact ${fact.field} (${fact.source})`);
|
|
2294
|
+
for (const proposal of plan.proposals)
|
|
2295
|
+
console.log(` proposal ${proposal.field} โ ${proposal.reason ?? proposal.source}`);
|
|
2296
|
+
for (const item of plan.invalid)
|
|
2297
|
+
console.log(` invalid ${item.field}: ${item.detail}`);
|
|
2298
|
+
for (const item of plan.unresolved) {
|
|
2299
|
+
console.log(` decide ${item.field} [${item.reason}]: ${item.detail}`);
|
|
2300
|
+
for (const [index, option] of (item.options ?? []).entries()) {
|
|
2301
|
+
console.log(` ${index + 1}. ${option}${item.recommended === index ? ' โ recommended' : ''}`);
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
for (const action of actions)
|
|
2305
|
+
console.log(`\nIssue it: ${action.display}`);
|
|
2306
|
+
if (forController) {
|
|
2307
|
+
console.log(`\nThe contract holds. Issuing it is the Controller's โ ${plan.issuance.detail}:`);
|
|
2308
|
+
console.log(` ${forController.display}`);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
// ์ฌ๋์ด ์ ํ ๊ฒ์ด ๋จ์๊ฑฐ๋ ์ด์์ด ์ฑ๋ฆฝํ์ง ์์ผ๋ฉด 1์ด๋ค โ setup plan๊ณผ ๊ฐ์ ๊ท์น.
|
|
2312
|
+
return plan.status === 'READY_TO_ISSUE' ? 0 : 1;
|
|
2313
|
+
}
|
|
1843
2314
|
async function runSession(command, target, values, store, resolved) {
|
|
1844
2315
|
// Profile์ด ์ ํ Role ๋ฒ์์ ๊ธ์ง๊ฐ ์ฌ๊ธฐ๊น์ง ์์ผ ์ค์ ๋ก ๊ฐ์ ๋๋ค.
|
|
1845
2316
|
// ์ ์ฑ
์์ด ๋ง๋ค๋ฉด ๋ถ์ด ์๋ ํ๋ก์ ํธ์์๋ ๊ณ์ฝ ๊ฒ์ฌ๊ฐ ํต์งธ๋ก ๋น์ด๋ฒ๋ฆฐ๋ค.
|
|
@@ -1863,6 +2334,10 @@ async function runSession(command, target, values, store, resolved) {
|
|
|
1863
2334
|
}
|
|
1864
2335
|
return 0;
|
|
1865
2336
|
}
|
|
2337
|
+
// `plan` ์ **์์ง ์ธ์
์ด ์์ ๋** ๋ถ๋ฅด๋ ๊ฒ์ด๋ฏ๋ก id๋ฅผ ์๊ตฌํ์ง ์๋๋ค. ์ด์์ id๊ฐ
|
|
2338
|
+
// ์๋ค๋ ์ฌ์ค ์์ฒด๊ฐ ํ์ ๋์์ด๋ค (์์ผ๋ฉด ๊ทธ๊ฒ์ด unresolved๋ก ๋์จ๋ค).
|
|
2339
|
+
if (command === 'plan')
|
|
2340
|
+
return runSessionPlan(values, store, resolved);
|
|
1866
2341
|
if (!target) {
|
|
1867
2342
|
console.error(`Usage: asc session ${command ?? '<command>'} <SESSION_ID>`);
|
|
1868
2343
|
return 2;
|