@guanlin4924/devflow-pi 0.1.15 → 0.1.17
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/package.json +1 -1
- package/plugins/devflow-core/extensions/devflow-core.ts +425 -54
- package/plugins/devflow-core/skills/workflow-orchestrator/SKILL.md +3 -2
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_assessment.rb +458 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_brief.rb +256 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_constraints.rb +155 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/architecture_feasibility.rb +176 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/control_io.rb +46 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/execution_contract.rb +94 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/init_state.rb +2 -1
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/machine_evidence.rb +112 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/requirement_graph.rb +646 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/runtime_context_collector.rb +210 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/stale_check.rb +56 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/static_runtime_context_collector.rb +518 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/validate_state.rb +140 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/scripts/workload_constraint.rb +57 -0
- package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml +88 -2
- package/plugins/devflow-core/skills/workflow-pipeline/SKILL.md +3 -2
- package/plugins/devflow-core/skills/workflow-project-context/SKILL.md +17 -1
- package/plugins/devflow-design/skills/workflow-architecture-feasibility/SKILL.md +37 -0
- package/plugins/devflow-design/skills/workflow-architecture-feasibility/agents/openai.yaml +4 -0
- package/plugins/devflow-design/skills/workflow-backend-tech-spec/SKILL.md +7 -2
- package/plugins/devflow-design/skills/workflow-frontend-tech-spec/SKILL.md +6 -1
- package/plugins/devflow-requirements/skills/requirement-feasibility-review/SKILL.md +4 -0
- package/plugins/devflow-requirements/skills/workflow-domain-modeling/SKILL.md +4 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-baseline/SKILL.md +4 -0
- package/plugins/devflow-requirements/skills/workflow-requirement-triage/SKILL.md +4 -0
- package/src/cli.ts +2 -1
- package/src/runtime.ts +2 -1
|
@@ -6,6 +6,8 @@ require "optparse"
|
|
|
6
6
|
require "yaml"
|
|
7
7
|
require_relative "control_io"
|
|
8
8
|
require_relative "phase_ownership"
|
|
9
|
+
require_relative "requirement_graph"
|
|
10
|
+
require_relative "architecture_feasibility"
|
|
9
11
|
|
|
10
12
|
module WorkflowStateValidator
|
|
11
13
|
REQUIRED_STATE_FIELDS = %w[
|
|
@@ -76,6 +78,26 @@ module WorkflowStateValidator
|
|
|
76
78
|
validate_completed_outputs(issues, root, state, step_by_id, completed_ids, artifact_by_path, strict_artifact_status)
|
|
77
79
|
validate_waiting_checkpoint(issues, root, state, step_by_id, artifact_by_path, strict_artifact_status)
|
|
78
80
|
validate_current_in_progress_output_drift(issues, root, state, step_by_id, artifact_by_path)
|
|
81
|
+
graph_gate = workflow.dig("governance", "requirement_graph_gate").to_s
|
|
82
|
+
governed_steps = %w[requirement-baseline api-contract architecture-feasibility integration-verify change-plan execute verify]
|
|
83
|
+
# A historical completed state is never rolled back solely because it has
|
|
84
|
+
# no v2 graph/evidence. Its first new governed step, however, must satisfy
|
|
85
|
+
# the new contract before it can advance.
|
|
86
|
+
strict_requirement_graph = graph_gate == "enforced" && (governed_steps.include?(state["current_step"]) || completed_ids.any? { |id| governed_steps.include?(id) })
|
|
87
|
+
observe_requirement_graph(issues, root, state, strict: strict_requirement_graph)
|
|
88
|
+
# Migration is intentionally non-destructive: pre-v2 completed steps are
|
|
89
|
+
# visible as unattested, never rewritten, rolled back, or auto-rerun.
|
|
90
|
+
if state["governance_started_revision"].nil?
|
|
91
|
+
legacy_steps = completed_ids.select { |id| governed_steps.include?(id) }
|
|
92
|
+
if legacy_steps.any?
|
|
93
|
+
issues << issue(
|
|
94
|
+
"warning",
|
|
95
|
+
"legacy_unattested",
|
|
96
|
+
"Historical governed steps predate Evidence Pack v2 and are report-only",
|
|
97
|
+
steps: legacy_steps
|
|
98
|
+
)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
79
101
|
|
|
80
102
|
ok = issues.none? { |entry| entry["severity"] == "error" }
|
|
81
103
|
result(ok, state_path, workflow_path, registry_path, issues)
|
|
@@ -263,6 +285,43 @@ module WorkflowStateValidator
|
|
|
263
285
|
end
|
|
264
286
|
end
|
|
265
287
|
|
|
288
|
+
# P1 observation mode: existing projects must not become invalid merely
|
|
289
|
+
# because they predate governance graphs. Once a graph exists, surface its
|
|
290
|
+
# structural failures through state inspection so operators can fix them
|
|
291
|
+
# before the corresponding checkpoint is upgraded to fail-closed.
|
|
292
|
+
def observe_requirement_graph(issues, root, state, strict: false)
|
|
293
|
+
path, relative = RequirementGraph.graph_path(root, state["current_feature"])
|
|
294
|
+
unless File.exist?(path)
|
|
295
|
+
issues << issue(strict ? "error" : "warning", "requirement_graph_missing", "Requirement governance graph is missing", path: relative) if strict
|
|
296
|
+
return
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
graph, = RequirementGraph.load_graph(root, state["current_feature"])
|
|
300
|
+
errors = RequirementGraph.validate(graph)
|
|
301
|
+
if errors.any?
|
|
302
|
+
issues << issue(
|
|
303
|
+
strict ? "error" : "warning",
|
|
304
|
+
"requirement_graph_observe_failed",
|
|
305
|
+
"Requirement governance graph has structural gaps (observation mode)",
|
|
306
|
+
path: relative,
|
|
307
|
+
graph_revision: graph["revision"],
|
|
308
|
+
errors: errors
|
|
309
|
+
)
|
|
310
|
+
end
|
|
311
|
+
return if Array(graph["stale"]).empty?
|
|
312
|
+
|
|
313
|
+
issues << issue(
|
|
314
|
+
strict ? "error" : "warning",
|
|
315
|
+
"requirement_graph_needs_recheck",
|
|
316
|
+
"Requirement governance graph has downstream nodes awaiting recheck (observation mode)",
|
|
317
|
+
path: relative,
|
|
318
|
+
graph_revision: graph["revision"],
|
|
319
|
+
stale: graph["stale"]
|
|
320
|
+
)
|
|
321
|
+
rescue ArgumentError => error
|
|
322
|
+
issues << issue("warning", "requirement_graph_observe_failed", error.message)
|
|
323
|
+
end
|
|
324
|
+
|
|
266
325
|
def validate_step_outputs(issues, root, state, step, artifact_by_path, strict_artifact_status, waiting_checkpoint)
|
|
267
326
|
Array(step["outputs"]).each do |output|
|
|
268
327
|
next unless output["required"]
|
|
@@ -320,6 +379,8 @@ module WorkflowStateValidator
|
|
|
320
379
|
validate_requirement_feasibility_review_gate(issues, step, data)
|
|
321
380
|
validate_requirement_baseline_gate(issues, step, data)
|
|
322
381
|
validate_api_contract_gate(issues, step, data)
|
|
382
|
+
validate_architecture_feasibility_gate(issues, step, data)
|
|
383
|
+
validate_architecture_consumption_gate(issues, root, state, step, data)
|
|
323
384
|
validate_api_call_guide_gate(issues, step, data)
|
|
324
385
|
validate_frontend_tech_spec_gate(issues, step, data)
|
|
325
386
|
validate_api_supplement_gate(issues, step, data)
|
|
@@ -454,6 +515,85 @@ module WorkflowStateValidator
|
|
|
454
515
|
end
|
|
455
516
|
end
|
|
456
517
|
|
|
518
|
+
# P2 is intentionally graduated: only a structurally-derived full
|
|
519
|
+
# assessment fail-closes. Lightweight incomplete work remains visible to its
|
|
520
|
+
# technical-spec consumers rather than forcing every small feature through
|
|
521
|
+
# an invented NFR exercise.
|
|
522
|
+
def validate_architecture_feasibility_gate(issues, step, data)
|
|
523
|
+
return unless step["id"] == "architecture-feasibility"
|
|
524
|
+
|
|
525
|
+
level = data["assessment_level"]
|
|
526
|
+
status = data["assessment_status"]
|
|
527
|
+
comparison = data["comparison_status"]
|
|
528
|
+
unless %w[not_triggered lightweight full].include?(level)
|
|
529
|
+
issues << issue("error", "architecture_assessment_level_invalid", "Architecture assessment level is invalid", step: step["id"], level: level)
|
|
530
|
+
return
|
|
531
|
+
end
|
|
532
|
+
unless %w[ready incomplete].include?(status)
|
|
533
|
+
issues << issue("error", "architecture_assessment_status_invalid", "Architecture assessment status is invalid", step: step["id"], status: status)
|
|
534
|
+
return
|
|
535
|
+
end
|
|
536
|
+
unless %w[not_required missing awaiting_user_confirmation missing_risk awaiting_risk_confirmation confirmed].include?(comparison)
|
|
537
|
+
issues << issue("error", "architecture_comparison_status_invalid", "Architecture comparison status is invalid", step: step["id"], comparison_status: comparison)
|
|
538
|
+
return
|
|
539
|
+
end
|
|
540
|
+
return unless level == "full"
|
|
541
|
+
return if status == "ready" && comparison == "confirmed"
|
|
542
|
+
|
|
543
|
+
issues << issue(
|
|
544
|
+
"error",
|
|
545
|
+
"architecture_full_assessment_incomplete",
|
|
546
|
+
"A full architecture assessment requires ready inputs plus confirmed decision and risk treatment before technical specifications.",
|
|
547
|
+
step: step["id"],
|
|
548
|
+
assessment_status: status,
|
|
549
|
+
comparison_status: comparison
|
|
550
|
+
)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# A technical spec does not merely claim that it considered architecture. It
|
|
554
|
+
# pins the exact Core-derived brief it consumed. Compare the pin both to the
|
|
555
|
+
# brief and to the current graph/context so an upstream edit cannot leave a
|
|
556
|
+
# convincing but obsolete spec looking fresh.
|
|
557
|
+
def validate_architecture_consumption_gate(issues, root, state, step, data)
|
|
558
|
+
return unless %w[frontend-tech-spec backend-tech-spec].include?(step["id"])
|
|
559
|
+
|
|
560
|
+
feature = state["current_feature"]
|
|
561
|
+
brief_path = File.join(root, ".planning", "features", feature, "architecture-brief.meta.json")
|
|
562
|
+
unless File.file?(brief_path)
|
|
563
|
+
issues << issue("error", "architecture_brief_meta_missing", "Technical spec cannot be validated without the architecture brief meta", step: step["id"], path: brief_path)
|
|
564
|
+
return
|
|
565
|
+
end
|
|
566
|
+
brief = JSON.parse(File.read(brief_path))
|
|
567
|
+
expected = {
|
|
568
|
+
"architecture_brief_revision" => brief["brief_revision"],
|
|
569
|
+
"architecture_graph_revision" => brief["graph_revision"],
|
|
570
|
+
"architecture_static_context_snapshot_revision" => brief["static_context_snapshot_revision"],
|
|
571
|
+
"architecture_comparison_status" => brief["comparison_status"]
|
|
572
|
+
}
|
|
573
|
+
expected.each do |field, value|
|
|
574
|
+
next if data[field] == value
|
|
575
|
+
|
|
576
|
+
issues << issue("error", "architecture_consumption_pin_mismatch", "Technical spec architecture pin differs from the Core-derived brief", step: step["id"], field: field, spec_value: data[field], brief_value: value)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
graph, = RequirementGraph.load_graph(root, feature)
|
|
580
|
+
if brief["graph_revision"] != graph["revision"]
|
|
581
|
+
issues << issue("error", "architecture_brief_graph_stale", "Architecture brief was derived from a stale graph revision", step: step["id"], brief_revision: brief["graph_revision"], graph_revision: graph["revision"])
|
|
582
|
+
end
|
|
583
|
+
current_context = ArchitectureFeasibility.safe_static_context(root)
|
|
584
|
+
current_context_revision = current_context["available"] ? current_context["snapshot_revision"] : nil
|
|
585
|
+
if brief["static_context_snapshot_revision"] != current_context_revision
|
|
586
|
+
issues << issue("error", "architecture_brief_context_stale", "Architecture brief was derived from a stale static-context snapshot", step: step["id"], brief_revision: brief["static_context_snapshot_revision"], context_revision: current_context_revision)
|
|
587
|
+
end
|
|
588
|
+
if brief["assessment_level"] == "full" && brief["comparison_status"] != "confirmed"
|
|
589
|
+
issues << issue("error", "architecture_brief_full_unconfirmed", "Technical spec cannot consume an unconfirmed full architecture assessment", step: step["id"], comparison_status: brief["comparison_status"])
|
|
590
|
+
end
|
|
591
|
+
rescue JSON::ParserError => error
|
|
592
|
+
issues << issue("error", "architecture_brief_meta_invalid", error.message, step: step["id"], path: brief_path)
|
|
593
|
+
rescue ArgumentError => error
|
|
594
|
+
issues << issue("error", "architecture_brief_graph_invalid", error.message, step: step["id"])
|
|
595
|
+
end
|
|
596
|
+
|
|
457
597
|
def validate_api_call_guide_gate(issues, step, data)
|
|
458
598
|
return unless step["id"] == "api-call-guide"
|
|
459
599
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Workload constraint validator (P1 NFR). Source-status driven: measured /
|
|
5
|
+
# contracted require evidence; approved_assumption requires owner +
|
|
6
|
+
# observability + review date + escalation trigger; unknown carries no
|
|
7
|
+
# evidence requirement but is only advisory.
|
|
8
|
+
require "json"
|
|
9
|
+
require "optparse"
|
|
10
|
+
|
|
11
|
+
module WorkloadConstraint
|
|
12
|
+
SOURCE_STATUSES = %w[measured contracted approved_assumption unknown].freeze
|
|
13
|
+
METRICS = %w[peak_qps data_growth rpo rto p95_latency].freeze
|
|
14
|
+
APPROVED_ASSUMPTION_FIELDS = %w[owner observability_metric review_date escalation_trigger].freeze
|
|
15
|
+
|
|
16
|
+
module_function
|
|
17
|
+
|
|
18
|
+
def validate(constraint)
|
|
19
|
+
errors = []
|
|
20
|
+
errors << "workload_ref is required" if constraint["workload_ref"].to_s.empty?
|
|
21
|
+
unless constraint["workload_ref"].to_s.match?(/\A(BEH|SL|API)-\d+\z/)
|
|
22
|
+
errors << "workload_ref must reference BEH/SL/API"
|
|
23
|
+
end
|
|
24
|
+
errors << "metric is required" if constraint["metric"].to_s.empty?
|
|
25
|
+
errors << "invalid metric" if !constraint["metric"].to_s.empty? && !METRICS.include?(constraint["metric"])
|
|
26
|
+
errors << "source_status is required" if constraint["source_status"].to_s.empty?
|
|
27
|
+
errors << "invalid source_status" if !constraint["source_status"].to_s.empty? && !SOURCE_STATUSES.include?(constraint["source_status"])
|
|
28
|
+
target = constraint["target"]
|
|
29
|
+
errors << "target.value is required" unless target.is_a?(Hash) && !target["value"].to_s.empty?
|
|
30
|
+
case constraint["source_status"]
|
|
31
|
+
when "measured", "contracted"
|
|
32
|
+
errors << "evidence_ref is required for #{constraint["source_status"]}" if constraint["evidence_ref"].to_s.empty?
|
|
33
|
+
when "approved_assumption"
|
|
34
|
+
APPROVED_ASSUMPTION_FIELDS.each do |key|
|
|
35
|
+
errors << "approved_assumption requires #{key}" if constraint[key].to_s.empty?
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
errors.uniq
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
if __FILE__ == $PROGRAM_NAME
|
|
43
|
+
options = { constraint_json: nil }
|
|
44
|
+
command = ARGV.shift
|
|
45
|
+
OptionParser.new do |o|
|
|
46
|
+
o.on("--constraint-json JSON") { |v| options[:constraint_json] = v }
|
|
47
|
+
o.on("--json") { options[:json] = true }
|
|
48
|
+
end.parse!
|
|
49
|
+
begin
|
|
50
|
+
raise ArgumentError, "command must be validate" unless command == "validate"
|
|
51
|
+
constraint = JSON.parse(options[:constraint_json].to_s)
|
|
52
|
+
errors = WorkloadConstraint.validate(constraint)
|
|
53
|
+
{ "ok" => errors.empty?, "errors" => errors }
|
|
54
|
+
rescue StandardError => error
|
|
55
|
+
{ "ok" => false, "reason" => "workload_constraint_failed", "message" => error.message }
|
|
56
|
+
end.tap { |r| puts JSON.pretty_generate(r) }
|
|
57
|
+
end
|
package/plugins/devflow-core/skills/workflow-orchestrator/templates/feature-development.yaml
CHANGED
|
@@ -13,6 +13,43 @@ phase_scope:
|
|
|
13
13
|
failure_branch_enabled: true
|
|
14
14
|
parallel_window_enabled: true
|
|
15
15
|
|
|
16
|
+
# P2 preset: new work fail-closes at the defined checkpoints. Existing STATE
|
|
17
|
+
# files without governance_started_revision remain legacy_unattested and are
|
|
18
|
+
# only reported until their next newly-started governed step.
|
|
19
|
+
governance:
|
|
20
|
+
requirement_graph_gate: enforced
|
|
21
|
+
enforced_checkpoints:
|
|
22
|
+
- CP-1
|
|
23
|
+
- CP-API
|
|
24
|
+
- CP-2
|
|
25
|
+
- CP-3
|
|
26
|
+
step_checkers:
|
|
27
|
+
requirement-baseline:
|
|
28
|
+
- requirement-graph-check
|
|
29
|
+
- slice-independence-check
|
|
30
|
+
- acceptance-coverage-check
|
|
31
|
+
- change-impact-check
|
|
32
|
+
api-contract:
|
|
33
|
+
- requirement-graph-check
|
|
34
|
+
- contract-coverage-check
|
|
35
|
+
- change-impact-check
|
|
36
|
+
architecture-feasibility:
|
|
37
|
+
- requirement-graph-check
|
|
38
|
+
- change-impact-check
|
|
39
|
+
integration-verify:
|
|
40
|
+
- requirement-graph-check
|
|
41
|
+
- slice-independence-check
|
|
42
|
+
- contract-coverage-check
|
|
43
|
+
- change-impact-check
|
|
44
|
+
change-plan:
|
|
45
|
+
- requirement-graph-check
|
|
46
|
+
- slice-independence-check
|
|
47
|
+
- contract-coverage-check
|
|
48
|
+
- change-impact-check
|
|
49
|
+
verify:
|
|
50
|
+
- acceptance-coverage-check
|
|
51
|
+
- change-impact-check
|
|
52
|
+
|
|
16
53
|
artifact_registry:
|
|
17
54
|
source: ".planning/artifacts/index.yaml"
|
|
18
55
|
path_key: path
|
|
@@ -44,7 +81,7 @@ lessons_policy:
|
|
|
44
81
|
parallel_windows:
|
|
45
82
|
- id: dual-track-design
|
|
46
83
|
label: API contract based frontend/backend design parallel window
|
|
47
|
-
after_step:
|
|
84
|
+
after_step: architecture-feasibility
|
|
48
85
|
branch_steps:
|
|
49
86
|
- backend-tech-spec
|
|
50
87
|
- ui-spec
|
|
@@ -184,7 +221,7 @@ checkpoints:
|
|
|
184
221
|
- approve
|
|
185
222
|
- needs_fix
|
|
186
223
|
skip_policy: never
|
|
187
|
-
resume_behavior: "user confirms, then
|
|
224
|
+
resume_behavior: "user confirms, then run architecture feasibility review before Track A/Track B design"
|
|
188
225
|
CP-2:
|
|
189
226
|
name: Merge Gate confirmation
|
|
190
227
|
gate_after: integration-verify
|
|
@@ -438,12 +475,44 @@ steps:
|
|
|
438
475
|
traceability_status: { type: string, required: true }
|
|
439
476
|
checkpoint: CP-API
|
|
440
477
|
|
|
478
|
+
- id: architecture-feasibility
|
|
479
|
+
order: 18
|
|
480
|
+
label: Architecture feasibility
|
|
481
|
+
skill: workflow-architecture-feasibility
|
|
482
|
+
depends_on:
|
|
483
|
+
- api-contract
|
|
484
|
+
inputs:
|
|
485
|
+
- ".planning/requirements/baseline.md"
|
|
486
|
+
- ".planning/features/{feature}/api-contract.md"
|
|
487
|
+
- ".planning/requirements/{feature}/governance.json"
|
|
488
|
+
- ".context/static-runtime-context.json"
|
|
489
|
+
- ".planning/navigation/INDEX.md"
|
|
490
|
+
outputs:
|
|
491
|
+
- path: ".planning/features/{feature}/architecture-brief.md"
|
|
492
|
+
type: architecture-brief
|
|
493
|
+
required: true
|
|
494
|
+
meta_output:
|
|
495
|
+
path: ".planning/features/{feature}/architecture-brief.meta.json"
|
|
496
|
+
fields:
|
|
497
|
+
assessment_status: { type: string, required: true }
|
|
498
|
+
assessment_level: { type: string, required: true }
|
|
499
|
+
graph_revision: { type: integer, required: true }
|
|
500
|
+
static_context_snapshot_revision: { type: integer, required: false }
|
|
501
|
+
comparison_status: { type: string, required: true }
|
|
502
|
+
trigger_codes: { type: array, required: true }
|
|
503
|
+
unresolved_codes: { type: array, required: true }
|
|
504
|
+
decision_ids: { type: array, required: true }
|
|
505
|
+
confirmed_decision_ids: { type: array, required: true }
|
|
506
|
+
risk_ids: { type: array, required: true }
|
|
507
|
+
confirmed_risk_ids: { type: array, required: true }
|
|
508
|
+
|
|
441
509
|
- id: ui-spec
|
|
442
510
|
order: 20
|
|
443
511
|
label: UI spec
|
|
444
512
|
skill: workflow-ui-spec
|
|
445
513
|
depends_on:
|
|
446
514
|
- api-contract
|
|
515
|
+
- architecture-feasibility
|
|
447
516
|
inputs:
|
|
448
517
|
- ".planning/requirements/baseline.md"
|
|
449
518
|
- ".planning/features/{feature}/api-contract.md"
|
|
@@ -474,8 +543,11 @@ steps:
|
|
|
474
543
|
depends_on:
|
|
475
544
|
- feature-breakdown
|
|
476
545
|
- api-contract
|
|
546
|
+
- architecture-feasibility
|
|
477
547
|
inputs:
|
|
478
548
|
- ".planning/features/{feature}/api-contract.md"
|
|
549
|
+
- ".planning/features/{feature}/architecture-brief.md"
|
|
550
|
+
- ".planning/features/{feature}/architecture-brief.meta.json"
|
|
479
551
|
- ".planning/features/{feature}/功能点梳理.md"
|
|
480
552
|
- ".planning/features/{feature}/UI-SPEC.md"
|
|
481
553
|
- ".planning/navigation/INDEX.md"
|
|
@@ -492,6 +564,10 @@ steps:
|
|
|
492
564
|
component_count: { type: integer, required: true }
|
|
493
565
|
api_count: { type: integer, required: true }
|
|
494
566
|
api_gaps_count: { type: integer, required: true }
|
|
567
|
+
architecture_brief_revision: { type: integer, required: true }
|
|
568
|
+
architecture_graph_revision: { type: integer, required: true }
|
|
569
|
+
architecture_static_context_snapshot_revision: { type: integer, required: false }
|
|
570
|
+
architecture_comparison_status: { type: string, required: true }
|
|
495
571
|
|
|
496
572
|
- id: backend-tech-spec
|
|
497
573
|
order: 50
|
|
@@ -499,8 +575,11 @@ steps:
|
|
|
499
575
|
skill: workflow-backend-tech-spec
|
|
500
576
|
depends_on:
|
|
501
577
|
- api-contract
|
|
578
|
+
- architecture-feasibility
|
|
502
579
|
inputs:
|
|
503
580
|
- ".planning/features/{feature}/api-contract.md"
|
|
581
|
+
- ".planning/features/{feature}/architecture-brief.md"
|
|
582
|
+
- ".planning/features/{feature}/architecture-brief.meta.json"
|
|
504
583
|
- ".planning/requirements/baseline.md"
|
|
505
584
|
- ".planning/navigation/INDEX.md"
|
|
506
585
|
- ".planning/execution-contract.md"
|
|
@@ -509,6 +588,13 @@ steps:
|
|
|
509
588
|
- path: ".planning/features/{feature}/后端技术方案.md"
|
|
510
589
|
type: backend-tech-spec
|
|
511
590
|
required: true
|
|
591
|
+
meta_output:
|
|
592
|
+
path: ".planning/features/{feature}/后端技术方案.meta.json"
|
|
593
|
+
fields:
|
|
594
|
+
architecture_brief_revision: { type: integer, required: true }
|
|
595
|
+
architecture_graph_revision: { type: integer, required: true }
|
|
596
|
+
architecture_static_context_snapshot_revision: { type: integer, required: false }
|
|
597
|
+
architecture_comparison_status: { type: string, required: true }
|
|
512
598
|
|
|
513
599
|
- id: api-call-guide
|
|
514
600
|
order: 55
|
|
@@ -29,6 +29,7 @@ pipeline 本身不包含执行规则——所有门禁、CP 协议、失败分
|
|
|
29
29
|
| 8 | requirement-feasibility-review | 可实现性审查 |
|
|
30
30
|
| 10 | requirement-baseline | 需求基线 |
|
|
31
31
|
| 15 | api-contract | API 契约(分叉前共同事实) |
|
|
32
|
+
| 18 | architecture-feasibility | 架构可行性与方案比较(分叉前共同事实) |
|
|
32
33
|
| 20 | ui-spec | Track B:UI 设计规范 |
|
|
33
34
|
| 30 | feature-breakdown | Track B:功能点梳理 |
|
|
34
35
|
| 40 | backend-tech-spec | Track A:后端方案 |
|
|
@@ -46,8 +47,8 @@ pipeline 本身不包含执行规则——所有门禁、CP 协议、失败分
|
|
|
46
47
|
| 110 | update-navigation | 更新导航 |
|
|
47
48
|
| 120 | archive | 里程碑归档 |
|
|
48
49
|
|
|
49
|
-
- **`--track A`**:后端/API 轨道产物模式。可跑 `requirement-triage → requirement-wayfinder → domain-modeling → requirement-feasibility-review → requirement-baseline → api-contract → backend-tech-spec → api-call-guide`,但不能自动进入 `integration-verify / change-plan / execute`。
|
|
50
|
-
- **`--track B`**:前端/UI 轨道产物模式。要求 `api-contract`
|
|
50
|
+
- **`--track A`**:后端/API 轨道产物模式。可跑 `requirement-triage → requirement-wayfinder → domain-modeling → requirement-feasibility-review → requirement-baseline → api-contract → architecture-feasibility → backend-tech-spec → api-call-guide`,但不能自动进入 `integration-verify / change-plan / execute`。
|
|
51
|
+
- **`--track B`**:前端/UI 轨道产物模式。要求 `api-contract` 与 `architecture-feasibility` 已完成;新需求从需求主链开始,已有共同事实可跑 `ui-spec → feature-breakdown → frontend-tech-spec`,但不能自动进入 `change-plan / execute`。
|
|
51
52
|
- **未设置 track**:完整交付模式。必须完成双轨并通过 `integration-verify` 后才能进入 `change-plan`。
|
|
52
53
|
- **`--no-review`**:保留参数位,但当前双轨 workflow 不自动跳过 CP-2。Merge Gate 不能跳过。
|
|
53
54
|
|
|
@@ -35,6 +35,7 @@ Always create or update:
|
|
|
35
35
|
- `.planning/navigation/INDEX.md` — codebase registry: maps each codebase to its navigation file, plus rule package index and downstream read contract
|
|
36
36
|
- `.planning/navigation/{name}.md` — one file per codebase: framework, entries, conventions, commands (name comes from user-provided codebase name)
|
|
37
37
|
- `.planning/code-index/` — machine code intelligence index location; generated by `workflow-code-index` by default unless fast mode skips it
|
|
38
|
+
- `.context/static-runtime-context/` + `.context/static-runtime-context.json` — Core-owned, Git-bound static declarations snapshot; never a production-health or capacity assertion
|
|
38
39
|
- `.context/spec/design/` — conditional frontend design rule package; installed after code-index for projects with frontend codebases
|
|
39
40
|
- `.planning/project-context-run.json` — current-run evidence: run identity, code-index status, dynamically discovered depth specs, source paths, and source fingerprints
|
|
40
41
|
- `.context/spec/index.md` — generated technical specification registry: maps stack profiles and codebase specs
|
|
@@ -114,7 +115,7 @@ If `.planning/` already exists:
|
|
|
114
115
|
|
|
115
116
|
1. Read existing `.planning/PROJECT.md`, `.planning/STATE.md`, and `.planning/navigation/*.md` before writing.
|
|
116
117
|
2. Preserve user-authored business context, constraints, key decisions, and missing information unless the user explicitly asks to replace them.
|
|
117
|
-
3. Refresh only machine-derived fields. This includes: detected paths, frameworks, entries, commands, scan status, navigation index, rule package files (execution-contract.md, toolchain.md, rules/INDEX.md), **all currently discovered depth spec files (Step 7.4)**,
|
|
118
|
+
3. Refresh only machine-derived fields. This includes: detected paths, frameworks, entries, commands, scan status, navigation index, rule package files (execution-contract.md, toolchain.md, rules/INDEX.md), **all currently discovered depth spec files (Step 7.4)**, **code index (Step 6.5)**, and **static runtime-context (Step 6.5a)**. The presence of existing output files does NOT exempt a step from re-execution — machine-derived fields must be regenerated to reflect current codebase state.
|
|
118
119
|
4. If provided codebase locations differ from existing records, record the change in `STATE.md` under `Change Log`.
|
|
119
120
|
5. Never delete existing planning files during initialization. Preserve user-authored content in execution-contract.md and toolchain.md when refreshing machine-derived fields.
|
|
120
121
|
|
|
@@ -478,6 +479,21 @@ After full-mode commands succeed, set `code_index_status` to `complete`, use ski
|
|
|
478
479
|
|
|
479
480
|
Do not require users to manually run Python when they invoked this skill.
|
|
480
481
|
|
|
482
|
+
## Step 6.5a — Static Runtime Context Snapshot (REQUIRED)
|
|
483
|
+
|
|
484
|
+
After Step 6.5, collect the separate P1 static-context snapshot:
|
|
485
|
+
|
|
486
|
+
```text
|
|
487
|
+
devflow_static_runtime_context(action="collect")
|
|
488
|
+
devflow_static_runtime_context(action="inspect")
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
Run this in both full and fast modes. It reads the committed Git tree and may therefore collect manifest declarations even when code-index was intentionally skipped. Verify that the returned pointer exists and record the snapshot revision in the initialization summary.
|
|
492
|
+
|
|
493
|
+
Do not describe this snapshot as production topology, resource health, capacity, or a list of deployed services. Its P1 scope is repository declarations and explicitly supported platform manifests only; unsupported resource bindings, integrations, and jobs remain `unknown` until a later collector can prove them.
|
|
494
|
+
|
|
495
|
+
If the repository has no readable Git commit, retain the generated snapshot with incomplete coverage and record the limitation. Do not invent a working-tree baseline or silently skip the collection.
|
|
496
|
+
|
|
481
497
|
## Step 6.6 — Design Rule Package (Conditional Required)
|
|
482
498
|
|
|
483
499
|
This step belongs to project initialization, not feature design. It runs **after the code index is available** and before the context-spec package is finalized.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workflow-architecture-feasibility
|
|
3
|
+
description: "Use after API contract and before frontend/backend technical specifications to compare implementation paths against confirmed workload facts and repository-static context. Use for async or scheduled work, batch operations, external calls, fanout, migrations, workload/SLA constraints, or when a feature may not fit the current framework and integrations."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 架构可行性与方案比较
|
|
7
|
+
|
|
8
|
+
生成一份由 Core 派生的架构简报;不把自由 Markdown 当作架构真相,也不把仓库声明当成生产容量。
|
|
9
|
+
|
|
10
|
+
## 固定流程
|
|
11
|
+
|
|
12
|
+
1. 读取 `devflow_requirement_graph(action="inspect")`、`devflow_static_runtime_context(action="inspect")`、API 契约和需求基线。
|
|
13
|
+
2. 调用 `devflow_architecture_feasibility(feature=...)`。保留返回的 graph revision、static snapshot revision、触发码和未决码;不得自行改写等级。
|
|
14
|
+
3. 对命中的工作负载补充 candidate:先用 `devflow_architecture_constraint` 校验,再用 `devflow_requirement_graph(action="propose")` 写入。
|
|
15
|
+
- WSH 使用 `workload_shape`,并连接 `REQ/BEH/API → WSH`,relation 为 `shapes_workload`。
|
|
16
|
+
- WLC 使用 `workload_constraint`,并连接 `BEH/SL/API → WLC`,relation 为 `constrains_workload`。
|
|
17
|
+
- `unknown` 只能写缺口、责任人、截止 checkpoint;不能填 target、evidence 或 assumption。
|
|
18
|
+
4. 对 `lightweight` 或 `full` 且存在实质取舍的结果,提交 `decision_type: architecture_option_comparison` 的 `DECISION` candidate:
|
|
19
|
+
- `subject_refs` 只引用 WSH/WLC;WSH 用 `informs_decision` 连到 DECISION,WLC 用 `constrains_decision` 连到 DECISION。
|
|
20
|
+
- 每个 option 使用 `option_key`,并包含 `mechanism`、非空 `fact_refs`、非空 `tradeoffs`。
|
|
21
|
+
- `multiple_options` 至少两个机制不同的选项;没有实质替代时使用 `single_path`,不要凑 A/B/C。
|
|
22
|
+
- `recommendation_option_id` 是建议,不是自动决策。
|
|
23
|
+
5. 对 `full` 评估,提交 `risk_type: architecture_option_risk` 的 `RISK` candidate,连接 `DECISION/WSH/WLC → RISK`,relation 为 `has_architecture_risk`。必须写失败模式、影响、处理、处理方式、负责人和复核条件。
|
|
24
|
+
6. 只用 `devflow_requirement_graph(action="confirm")` 确认 WSH/WLC、架构 DECISION 和架构 RISK。Core 必须展示确认对话;确认方案比较时,用户确认的是显示的 `recommendation_option_id`,确认风险时只确认处理责任,不宣称生产风险已消失。
|
|
25
|
+
7. 调用 `devflow_architecture_brief(action="render")` 生成 `.planning/features/{feature}/architecture-brief.md` 及 meta。不得手写或补写简报正文。
|
|
26
|
+
|
|
27
|
+
## 不变量
|
|
28
|
+
|
|
29
|
+
- 静态上下文只说明提交到仓库的声明/引用;不说明生产资源、健康度、容量或监控余量。
|
|
30
|
+
- 数字没有 measured/contracted 证据时,保持 unknown;不得为通过检查编 QPS、DAU、数据量或阈值。
|
|
31
|
+
- `assessment_status: incomplete`、`comparison_status: missing` 或 `awaiting_*` 必须原样交给下游技术方案,不能写成“评估通过”。
|
|
32
|
+
- 已确认 WSH/WLC/架构 DECISION/RISK 不可原地更新;新建 candidate、重新连边,并让 stale 传播要求消费者复核。
|
|
33
|
+
- 不替用户选择方案、接受残余风险或伪造 CP 记录。
|
|
34
|
+
|
|
35
|
+
## 下游交接
|
|
36
|
+
|
|
37
|
+
前端和后端技术方案都必须读取 `architecture-brief.md` 和 `.meta.json`,并记录消费的 `graph_revision`、`static_context_snapshot_revision`、`brief_revision`。若 brief 不是 `comparison_status: confirmed`,只可把其未决项作为前提/风险写入方案,不能把推荐项变成已决定实现。
|
|
@@ -13,6 +13,8 @@ user-invocable: true
|
|
|
13
13
|
pattern: generator+tool-wrapper
|
|
14
14
|
inputs:
|
|
15
15
|
- .planning/features/{功能名}/api-contract.md
|
|
16
|
+
- .planning/features/{功能名}/architecture-brief.md
|
|
17
|
+
- .planning/features/{功能名}/architecture-brief.meta.json
|
|
16
18
|
- .planning/requirements/baseline.md
|
|
17
19
|
- .planning/features/{功能名}/功能点梳理.md (optional, Track B context when already available)
|
|
18
20
|
- .planning/PROJECT.md
|
|
@@ -73,8 +75,9 @@ allowed-tools:
|
|
|
73
75
|
- 影响 scope、语义、归属、兼容性或实现成本的未确认项,不得被当成已确认需求
|
|
74
76
|
- 若未确认项阻塞后端方案,询问用户;`--auto` 或无法询问时写入待确认事项和风险
|
|
75
77
|
7. 读取 `.planning/features/{功能名}/api-contract.md`。在双轨模式下,后端方案必须以 API 契约和需求基线作为权威输入,不得等待 Track B 的 `功能点梳理.md` 才开始。
|
|
76
|
-
8.
|
|
77
|
-
9. 若
|
|
78
|
+
8. 读取 `.planning/features/{功能名}/architecture-brief.md` 和 `.meta.json`,在文档开头记录消费的 `brief_revision`、`graph_revision` 和 `static_context_snapshot_revision`。`comparison_status=confirmed` 的选择可作为实现依据;其他状态只能作为风险或待确认前提,不得把 recommendation 写成已决定实现。若 `assessment_level=full` 但未 confirmed,停止并回到架构评估。
|
|
79
|
+
9. 若 `功能点梳理.md` 已存在,可作为测试可读上下文补充读取;若不存在,不阻塞 Track A。
|
|
80
|
+
10. 若 baseline、api-contract 或 `功能点梳理.md` 包含 `SL-*` 切片计划,读取 `skill://workflow-pipeline/references/slice-safety-guide.md`,只为当前执行切片生成后端方案。后置切片只可作为依赖上下文或后续范围,不得生成库表、接口、任务或运行时设计。
|
|
78
81
|
|
|
79
82
|
### 第二阶段:探索现有代码
|
|
80
83
|
|
|
@@ -208,6 +211,8 @@ If an older baseline still points to root `features/{功能名}/`, treat that as
|
|
|
208
211
|
|
|
209
212
|
### 第五阶段:结构化元数据
|
|
210
213
|
|
|
214
|
+
完成后写入 `.planning/features/{功能名}/后端技术方案.meta.json`。必须从 `architecture-brief.meta.json` 原样复制:`brief_revision → architecture_brief_revision`、`graph_revision → architecture_graph_revision`、`static_context_snapshot_revision → architecture_static_context_snapshot_revision`、`comparison_status → architecture_comparison_status`。不得凭记忆填写或改写这些值。
|
|
215
|
+
|
|
211
216
|
完成后写入 `.planning/features/{功能名}/后端技术方案.meta.json`,字段定义见 `feature-development.yaml` 中 `steps[backend-tech-spec].meta_output.fields`:`api_count`, `table_count`, `migration_count`。
|
|
212
217
|
|
|
213
218
|
## 注意事项
|
|
@@ -14,6 +14,8 @@ pattern: generator+tool-wrapper
|
|
|
14
14
|
inputs:
|
|
15
15
|
- .planning/features/{功能名}/功能点梳理.md
|
|
16
16
|
- .planning/features/{功能名}/UI-SPEC.md
|
|
17
|
+
- .planning/features/{功能名}/architecture-brief.md
|
|
18
|
+
- .planning/features/{功能名}/architecture-brief.meta.json
|
|
17
19
|
- .planning/requirements/baseline.md
|
|
18
20
|
- .planning/PROJECT.md
|
|
19
21
|
- .planning/navigation/INDEX.md
|
|
@@ -72,7 +74,8 @@ allowed-tools:
|
|
|
72
74
|
- 已确认的页面/交互/复用/替代方案决策必须进入前端方案
|
|
73
75
|
- 影响 scope、交互语义、组件归属、兼容性或实现成本的未确认项,不得被当成已确认需求
|
|
74
76
|
- 若未确认项阻塞前端方案,询问用户;`--auto` 或无法询问时写入待确认事项和风险
|
|
75
|
-
9.
|
|
77
|
+
9. 读取 `.planning/features/{功能名}/architecture-brief.md` 和 `.meta.json`,在文档开头记录消费的 `brief_revision`、`graph_revision` 和 `static_context_snapshot_revision`。只有 `comparison_status=confirmed` 的架构选择可改变请求编排、缓存、轮询或异步交互;未确认/未决项必须保留为风险或待确认事项。
|
|
78
|
+
10. 若 baseline 或 `功能点梳理.md` 包含 `SL-*` 切片计划,读取 `skill://workflow-pipeline/references/slice-safety-guide.md`,只为当前执行切片生成前端方案。后置切片只可作为依赖上下文或后续范围,不得生成路由、组件或 API 调用实现设计。
|
|
76
79
|
|
|
77
80
|
### 第二阶段:探索现有前端代码
|
|
78
81
|
|
|
@@ -170,6 +173,8 @@ If an older baseline still points to root `features/{功能名}/`, treat that as
|
|
|
170
173
|
|
|
171
174
|
完成后写入 `.planning/features/{功能名}/前端技术方案.meta.json`,字段定义见 `feature-development.yaml` 中 `steps[frontend-tech-spec].meta_output.fields`:`route_count`, `component_count`, `api_count`, `api_gaps_count`。
|
|
172
175
|
|
|
176
|
+
同时必须从 `architecture-brief.meta.json` 原样复制:`brief_revision → architecture_brief_revision`、`graph_revision → architecture_graph_revision`、`static_context_snapshot_revision → architecture_static_context_snapshot_revision`、`comparison_status → architecture_comparison_status`。不得凭记忆填写或改写这些值。
|
|
177
|
+
|
|
173
178
|
`api_gaps_count` 表示前端方案发现但 `api-contract.md` 未覆盖的接口缺口数量。若大于 0,必须由 `workflow-api-supplement` 处理并回写 API 契约后,才能进入 `integration-verify`。
|
|
174
179
|
|
|
175
180
|
## 注意事项
|
|
@@ -204,6 +204,10 @@ Before accepting the rebuttal or retracting the finding, re-open the cited raw s
|
|
|
204
204
|
|
|
205
205
|
## Quality Bar
|
|
206
206
|
|
|
207
|
+
## Governance Graph Candidate
|
|
208
|
+
|
|
209
|
+
Submit `risk` and `decision` candidates through `devflow_requirement_graph`, and add missing `behavior` candidates only when backed by a cited source. A `pass` review cannot promote candidates, clear stale nodes, or claim machine validation; it supplies structured candidates and evidence for the Core gate and human checkpoint.
|
|
210
|
+
|
|
207
211
|
The review must make it easy to trace every conclusion back to evidence. Include:
|
|
208
212
|
|
|
209
213
|
- flow inventory and critical capability chains;
|
|
@@ -130,6 +130,10 @@ Accepted
|
|
|
130
130
|
|
|
131
131
|
## Meta Output
|
|
132
132
|
|
|
133
|
+
## Governance Graph Candidate
|
|
134
|
+
|
|
135
|
+
Submit bounded candidates through `devflow_requirement_graph`: use `term` for shared language and `behavior` for actor, precondition, state transition, invariant, writes, side effects, failure, and recovery. Link candidates only with returned IDs. Never directly edit the canonical graph or mark a node confirmed; unresolved ownership remains a candidate and is reported in metadata.
|
|
136
|
+
|
|
133
137
|
`领域模型记录.meta.json` minimum fields:
|
|
134
138
|
|
|
135
139
|
```json
|
|
@@ -727,6 +727,10 @@ Completion gate: baseline and baseline.meta.json are written and contain no unre
|
|
|
727
727
|
|
|
728
728
|
### 7.4 产物完整性检查
|
|
729
729
|
|
|
730
|
+
### 7.4.1 Governance Graph Candidate
|
|
731
|
+
|
|
732
|
+
Before claiming baseline readiness, submit `requirement`、`rule`、`boundary`、`slice` and `acceptance` candidates through `devflow_requirement_graph`. Each requirement candidate must cite source IDs and reference behavior/acceptance IDs returned by the writer. Run `devflow_requirement_graph(action="validate")` and record its result in baseline metadata. Do not directly create `governance.json`, allocate IDs, or set candidate status to `confirmed`.
|
|
733
|
+
|
|
730
734
|
```markdown
|
|
731
735
|
- [ ] 每个原始需求映射到 FP-*/BR-*/BC-* 或 out-of-scope
|
|
732
736
|
- [ ] 追溯表完整,来源→FP 映射可验证
|
|
@@ -191,6 +191,10 @@ Ask at most one question, only when route cannot be decided without it. If the n
|
|
|
191
191
|
|
|
192
192
|
## Completion Rule
|
|
193
193
|
|
|
194
|
+
## Governance Graph Candidate
|
|
195
|
+
|
|
196
|
+
Before completion, inspect `devflow_requirement_graph` for the current feature. Submit only `source` or `code` candidate deltas for source material and repository facts discovered here. Read the returned graph revision after every accepted delta. Do not invent stable IDs, set a candidate to `confirmed`, or write `governance.json` directly.
|
|
197
|
+
|
|
194
198
|
Only tell `workflow-orchestrator` to complete `requirement-triage` after writing:
|
|
195
199
|
|
|
196
200
|
```json
|
package/src/cli.ts
CHANGED
|
@@ -14,7 +14,7 @@ function usage(): string {
|
|
|
14
14
|
" devflow-pi init [project]",
|
|
15
15
|
" devflow-pi doctor [project]",
|
|
16
16
|
" devflow-pi usage [project]",
|
|
17
|
-
" devflow-pi [project] [--resume [session-id]] [--prompt <text>] [--mcp]",
|
|
17
|
+
" devflow-pi [project] [--resume [session-id]] [--prompt <text>] [--mcp] [--yolo]",
|
|
18
18
|
].join("\n");
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -76,6 +76,7 @@ async function main(): Promise<void> {
|
|
|
76
76
|
originalOmpAgentDir,
|
|
77
77
|
resume: optionalOption(args, "--resume"),
|
|
78
78
|
enableMCP: args.includes("--mcp"),
|
|
79
|
+
approvalMode: args.includes("--yolo") ? "yolo" : "write",
|
|
79
80
|
});
|
|
80
81
|
}
|
|
81
82
|
|
package/src/runtime.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface RuntimeOptions {
|
|
|
13
13
|
hasUI?: boolean;
|
|
14
14
|
enableMCP?: boolean;
|
|
15
15
|
enableLsp?: boolean;
|
|
16
|
+
approvalMode?: "write" | "yolo";
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
const MANAGED_SETTINGS: Record<string, unknown> = {
|
|
@@ -54,7 +55,6 @@ const MANAGED_SETTINGS: Record<string, unknown> = {
|
|
|
54
55
|
"lsp.enabled": true,
|
|
55
56
|
"lsp.lazy": true,
|
|
56
57
|
"lsp.diagnosticsOnWrite": true,
|
|
57
|
-
"tools.approvalMode": "write",
|
|
58
58
|
};
|
|
59
59
|
|
|
60
60
|
export async function createEmbeddedRuntime(project: ProjectContext, options: RuntimeOptions = {}) {
|
|
@@ -92,6 +92,7 @@ export async function createEmbeddedRuntime(project: ProjectContext, options: Ru
|
|
|
92
92
|
agentDir: productAgentDir,
|
|
93
93
|
overrides: {
|
|
94
94
|
...MANAGED_SETTINGS,
|
|
95
|
+
"tools.approvalMode": options.approvalMode ?? "write",
|
|
95
96
|
// OMP 17.2.7 classifies extension-package skills behind the generic
|
|
96
97
|
// third-party toggle. Explicit custom roots keep ambient providers off
|
|
97
98
|
// while guaranteeing the packaged Devflow skills are present.
|